From 1ca5b9d2183f11bb8b69e04b19a7faf7f600a840 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 4 May 2008 01:31:42 -0400 Subject: power_supply: Support serial number in olpc_battery This adds serial number support to the OLPC battery driver. Signed-off-by: David Woodhouse Signed-off-by: Andres Salomon Signed-off-by: Anton Vorontsov --- drivers/power/olpc_battery.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index ab1e8289f07..7524a63a54c 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -84,6 +84,8 @@ static struct power_supply olpc_ac = { .get_property = olpc_ac_get_prop, }; +static char bat_serial[17]; /* Ick */ + /********************************************************************* * Battery properties *********************************************************************/ @@ -94,6 +96,7 @@ static int olpc_bat_get_property(struct power_supply *psy, int ret = 0; int16_t ec_word; uint8_t ec_byte; + uint64_t ser_buf; ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &ec_byte, 1); if (ret) @@ -241,6 +244,14 @@ static int olpc_bat_get_property(struct power_supply *psy, ec_word = be16_to_cpu(ec_word); val->intval = ec_word * 100 / 256; break; + case POWER_SUPPLY_PROP_SERIAL_NUMBER: + ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8); + if (ret) + return ret; + + sprintf(bat_serial, "%016llx", (long long)be64_to_cpu(ser_buf)); + val->strval = bat_serial; + break; default: ret = -EINVAL; break; @@ -260,6 +271,7 @@ static enum power_supply_property olpc_bat_props[] = { POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_TEMP_AMBIENT, POWER_SUPPLY_PROP_MANUFACTURER, + POWER_SUPPLY_PROP_SERIAL_NUMBER, }; /********************************************************************* -- cgit v1.2.3 From d7eb9e36c42504e87c7d92dd5c05cb6f2cf74d28 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Fri, 2 May 2008 13:41:58 -0700 Subject: power_supply: add eeprom dump file to olpc_battery's sysfs This allows you to dump 0x60 bytes from the battery's EEPROM (starting at address 0x20). Note that it does an EC command for each byte, so it's pretty slow. OTOH, if you want to grab just a single byte from somewhere in the EEPROM, you can do something like: dd bs=1 count=1 skip=16 if=/sys/class/power_supply/olpc-battery/eeprom | od -x Userspace battery collection/logging information needs this. Signed-off-by: Andres Salomon Cc: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: Anton Vorontsov --- drivers/power/olpc_battery.c | 49 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'drivers') diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index 7524a63a54c..f8dc2b18bb4 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -274,6 +274,48 @@ static enum power_supply_property olpc_bat_props[] = { POWER_SUPPLY_PROP_SERIAL_NUMBER, }; +/* EEPROM reading goes completely around the power_supply API, sadly */ + +#define EEPROM_START 0x20 +#define EEPROM_END 0x80 +#define EEPROM_SIZE (EEPROM_END - EEPROM_START) + +static ssize_t olpc_bat_eeprom_read(struct kobject *kobj, + struct bin_attribute *attr, char *buf, loff_t off, size_t count) +{ + uint8_t ec_byte; + int ret, end; + + if (off >= EEPROM_SIZE) + return 0; + if (off + count > EEPROM_SIZE) + count = EEPROM_SIZE - off; + + end = EEPROM_START + off + count; + for (ec_byte = EEPROM_START + off; ec_byte < end; ec_byte++) { + ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, + &buf[ec_byte - EEPROM_START], 1); + if (ret) { + printk(KERN_ERR "olpc-battery: EC command " + "EC_BAT_EEPROM @ 0x%x failed -" + " %d!\n", ec_byte, ret); + return -EIO; + } + } + + return count; +} + +static struct bin_attribute olpc_bat_eeprom = { + .attr = { + .name = "eeprom", + .mode = S_IRUGO, + .owner = THIS_MODULE, + }, + .size = 0, + .read = olpc_bat_eeprom_read, +}; + /********************************************************************* * Initialisation *********************************************************************/ @@ -327,8 +369,14 @@ static int __init olpc_bat_init(void) if (ret) goto battery_failed; + ret = device_create_bin_file(olpc_bat.dev, &olpc_bat_eeprom); + if (ret) + goto eeprom_failed; + goto success; +eeprom_failed: + power_supply_unregister(&olpc_bat); battery_failed: power_supply_unregister(&olpc_ac); ac_failed: @@ -339,6 +387,7 @@ success: static void __exit olpc_bat_exit(void) { + device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom); power_supply_unregister(&olpc_bat); power_supply_unregister(&olpc_ac); platform_device_unregister(bat_pdev); -- cgit v1.2.3 From b2bd8a3bcdd18101eb5d85c267c1a1fb8ce9acc7 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Fri, 2 May 2008 13:41:59 -0700 Subject: power_supply: cleanup of the OLPC battery driver Move portions of the massive switch statement into functions. The layout of this thing has already caused one bug (a break in the wrong place), it needed to shrink. Signed-off-by: Andres Salomon Cc: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: Anton Vorontsov --- drivers/power/olpc_battery.c | 191 ++++++++++++++++++++++++++----------------- 1 file changed, 118 insertions(+), 73 deletions(-) (limited to 'drivers') diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index f8dc2b18bb4..d5fe6f0c9de 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -86,6 +86,117 @@ static struct power_supply olpc_ac = { static char bat_serial[17]; /* Ick */ +static int olpc_bat_get_status(union power_supply_propval *val, uint8_t ec_byte) +{ + if (olpc_platform_info.ecver > 0x44) { + if (ec_byte & BAT_STAT_CHARGING) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else if (ec_byte & BAT_STAT_DISCHARGING) + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + else if (ec_byte & BAT_STAT_FULL) + val->intval = POWER_SUPPLY_STATUS_FULL; + else /* er,... */ + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + } else { + /* Older EC didn't report charge/discharge bits */ + if (!(ec_byte & BAT_STAT_AC)) /* No AC means discharging */ + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + else if (ec_byte & BAT_STAT_FULL) + val->intval = POWER_SUPPLY_STATUS_FULL; + else /* Not _necessarily_ true but EC doesn't tell all yet */ + val->intval = POWER_SUPPLY_STATUS_CHARGING; + } + + return 0; +} + +static int olpc_bat_get_health(union power_supply_propval *val) +{ + uint8_t ec_byte; + int ret; + + ret = olpc_ec_cmd(EC_BAT_ERRCODE, NULL, 0, &ec_byte, 1); + if (ret) + return ret; + + switch (ec_byte) { + case 0: + val->intval = POWER_SUPPLY_HEALTH_GOOD; + break; + + case BAT_ERR_OVERTEMP: + val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; + break; + + case BAT_ERR_OVERVOLTAGE: + val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + break; + + case BAT_ERR_INFOFAIL: + case BAT_ERR_OUT_OF_CONTROL: + case BAT_ERR_ID_FAIL: + case BAT_ERR_ACR_FAIL: + val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; + break; + + default: + /* Eep. We don't know this failure code */ + ret = -EIO; + } + + return ret; +} + +static int olpc_bat_get_mfr(union power_supply_propval *val) +{ + uint8_t ec_byte; + int ret; + + ec_byte = BAT_ADDR_MFR_TYPE; + ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1); + if (ret) + return ret; + + switch (ec_byte >> 4) { + case 1: + val->strval = "Gold Peak"; + break; + case 2: + val->strval = "BYD"; + break; + default: + val->strval = "Unknown"; + break; + } + + return ret; +} + +static int olpc_bat_get_tech(union power_supply_propval *val) +{ + uint8_t ec_byte; + int ret; + + ec_byte = BAT_ADDR_MFR_TYPE; + ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1); + if (ret) + return ret; + + switch (ec_byte & 0xf) { + case 1: + val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH; + break; + case 2: + val->intval = POWER_SUPPLY_TECHNOLOGY_LiFe; + break; + default: + val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; + break; + } + + return ret; +} + /********************************************************************* * Battery properties *********************************************************************/ @@ -113,25 +224,10 @@ static int olpc_bat_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_STATUS: - if (olpc_platform_info.ecver > 0x44) { - if (ec_byte & BAT_STAT_CHARGING) - val->intval = POWER_SUPPLY_STATUS_CHARGING; - else if (ec_byte & BAT_STAT_DISCHARGING) - val->intval = POWER_SUPPLY_STATUS_DISCHARGING; - else if (ec_byte & BAT_STAT_FULL) - val->intval = POWER_SUPPLY_STATUS_FULL; - else /* er,... */ - val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; - } else { - /* Older EC didn't report charge/discharge bits */ - if (!(ec_byte & BAT_STAT_AC)) /* No AC means discharging */ - val->intval = POWER_SUPPLY_STATUS_DISCHARGING; - else if (ec_byte & BAT_STAT_FULL) - val->intval = POWER_SUPPLY_STATUS_FULL; - else /* Not _necessarily_ true but EC doesn't tell all yet */ - val->intval = POWER_SUPPLY_STATUS_CHARGING; - break; - } + ret = olpc_bat_get_status(val, ec_byte); + if (ret) + return ret; + break; case POWER_SUPPLY_PROP_PRESENT: val->intval = !!(ec_byte & BAT_STAT_PRESENT); break; @@ -140,72 +236,21 @@ static int olpc_bat_get_property(struct power_supply *psy, if (ec_byte & BAT_STAT_DESTROY) val->intval = POWER_SUPPLY_HEALTH_DEAD; else { - ret = olpc_ec_cmd(EC_BAT_ERRCODE, NULL, 0, &ec_byte, 1); + ret = olpc_bat_get_health(val); if (ret) return ret; - - switch (ec_byte) { - case 0: - val->intval = POWER_SUPPLY_HEALTH_GOOD; - break; - - case BAT_ERR_OVERTEMP: - val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; - break; - - case BAT_ERR_OVERVOLTAGE: - val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; - break; - - case BAT_ERR_INFOFAIL: - case BAT_ERR_OUT_OF_CONTROL: - case BAT_ERR_ID_FAIL: - case BAT_ERR_ACR_FAIL: - val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; - break; - - default: - /* Eep. We don't know this failure code */ - return -EIO; - } } break; case POWER_SUPPLY_PROP_MANUFACTURER: - ec_byte = BAT_ADDR_MFR_TYPE; - ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1); + ret = olpc_bat_get_mfr(val); if (ret) return ret; - - switch (ec_byte >> 4) { - case 1: - val->strval = "Gold Peak"; - break; - case 2: - val->strval = "BYD"; - break; - default: - val->strval = "Unknown"; - break; - } break; case POWER_SUPPLY_PROP_TECHNOLOGY: - ec_byte = BAT_ADDR_MFR_TYPE; - ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1); + ret = olpc_bat_get_tech(val); if (ret) return ret; - - switch (ec_byte & 0xf) { - case 1: - val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH; - break; - case 2: - val->intval = POWER_SUPPLY_TECHNOLOGY_LiFe; - break; - default: - val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; - break; - } break; case POWER_SUPPLY_PROP_VOLTAGE_AVG: ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2); -- cgit v1.2.3 From 484d6d50cca3941db6e063113d124333aed0abc0 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Fri, 2 May 2008 13:41:59 -0700 Subject: power_supply: bump EC version check that we refuse to run with in olpc_battery Refuse to run with an EC < 0x44. We're playing it safe, and this is a pretty old EC version. Also, add a comment about why we're checking the EC version. Signed-off-by: Andres Salomon Cc: David Woodhouse Signed-off-by: Andrew Morton Signed-off-by: Anton Vorontsov --- drivers/power/olpc_battery.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index d5fe6f0c9de..c8b596a7fc9 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -389,8 +389,14 @@ static int __init olpc_bat_init(void) if (!olpc_platform_info.ecver) return -ENXIO; - if (olpc_platform_info.ecver < 0x43) { - printk(KERN_NOTICE "OLPC EC version 0x%02x too old for battery driver.\n", olpc_platform_info.ecver); + + /* + * We've seen a number of EC protocol changes; this driver requires + * the latest EC protocol, supported by 0x44 and above. + */ + if (olpc_platform_info.ecver < 0x44) { + printk(KERN_NOTICE "OLPC EC version 0x%02x too old for " + "battery driver.\n", olpc_platform_info.ecver); return -ENXIO; } -- cgit v1.2.3 From 8e552c36d90c03d2cabf5373788998966751b609 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Mon, 12 May 2008 21:46:29 -0400 Subject: power_supply: add CHARGE_COUNTER property and olpc_battery support for it This adds PROP_CHARGE_COUNTER to the power supply class (documenting it as well). The OLPC battery driver uses this for spitting out its ACR values (in uAh). We have some rounding errors (the data sheet claims 416.7, the math actually works out to 416.666667, so we're forced to choose between overflows or precision loss. I chose precision loss, and stuck w/ data sheet values), but I don't think anyone will care that much. Signed-off-by: Andres Salomon Signed-off-by: Anton Vorontsov --- drivers/power/olpc_battery.c | 11 ++++++++++- drivers/power/power_supply_sysfs.c | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index c8b596a7fc9..9dd1589733c 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -19,7 +19,7 @@ #define EC_BAT_VOLTAGE 0x10 /* uint16_t, *9.76/32, mV */ #define EC_BAT_CURRENT 0x11 /* int16_t, *15.625/120, mA */ -#define EC_BAT_ACR 0x12 +#define EC_BAT_ACR 0x12 /* int16_t, *416.7, µAh */ #define EC_BAT_TEMP 0x13 /* uint16_t, *100/256, °C */ #define EC_AMB_TEMP 0x14 /* uint16_t, *100/256, °C */ #define EC_BAT_STATUS 0x15 /* uint8_t, bitmask */ @@ -289,6 +289,14 @@ static int olpc_bat_get_property(struct power_supply *psy, ec_word = be16_to_cpu(ec_word); val->intval = ec_word * 100 / 256; break; + case POWER_SUPPLY_PROP_CHARGE_COUNTER: + ret = olpc_ec_cmd(EC_BAT_ACR, NULL, 0, (void *)&ec_word, 2); + if (ret) + return ret; + + ec_word = be16_to_cpu(ec_word); + val->intval = ec_word * 4167 / 10; + break; case POWER_SUPPLY_PROP_SERIAL_NUMBER: ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8); if (ret) @@ -317,6 +325,7 @@ static enum power_supply_property olpc_bat_props[] = { POWER_SUPPLY_PROP_TEMP_AMBIENT, POWER_SUPPLY_PROP_MANUFACTURER, POWER_SUPPLY_PROP_SERIAL_NUMBER, + POWER_SUPPLY_PROP_CHARGE_COUNTER, }; /* EEPROM reading goes completely around the power_supply API, sadly */ diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index c444d6b10c5..82e1246eeb0 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -99,6 +99,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(charge_empty), POWER_SUPPLY_ATTR(charge_now), POWER_SUPPLY_ATTR(charge_avg), + POWER_SUPPLY_ATTR(charge_counter), POWER_SUPPLY_ATTR(energy_full_design), POWER_SUPPLY_ATTR(energy_empty_design), POWER_SUPPLY_ATTR(energy_full), -- cgit v1.2.3 From 75d8807962fc7529b4946e9ec92cae197be5a967 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Wed, 14 May 2008 16:20:38 -0700 Subject: power_supply: fix up CHARGE_COUNTER output to be more precise As Richard Smith pointed out, ACR * 6250 / 15 provides for less precision loss than ACR * 4167 / 10, _and_ it doesn't overflow. Switch to using that equation for CHARGE_COUNTER. Signed-off-by: Andres Salomon Cc: "Richard A. Smith" Signed-off-by: Andrew Morton Signed-off-by: Anton Vorontsov --- drivers/power/olpc_battery.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index 9dd1589733c..32570af3c5c 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -19,7 +19,7 @@ #define EC_BAT_VOLTAGE 0x10 /* uint16_t, *9.76/32, mV */ #define EC_BAT_CURRENT 0x11 /* int16_t, *15.625/120, mA */ -#define EC_BAT_ACR 0x12 /* int16_t, *416.7, µAh */ +#define EC_BAT_ACR 0x12 /* int16_t, *6250/15, µAh */ #define EC_BAT_TEMP 0x13 /* uint16_t, *100/256, °C */ #define EC_AMB_TEMP 0x14 /* uint16_t, *100/256, °C */ #define EC_BAT_STATUS 0x15 /* uint8_t, bitmask */ @@ -295,7 +295,7 @@ static int olpc_bat_get_property(struct power_supply *psy, return ret; ec_word = be16_to_cpu(ec_word); - val->intval = ec_word * 4167 / 10; + val->intval = ec_word * 6250 / 15; break; case POWER_SUPPLY_PROP_SERIAL_NUMBER: ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8); -- cgit v1.2.3 From fece418418f51e92dd7e67e17c5e3fe5a28d3279 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 24 Jun 2008 18:51:07 +0400 Subject: power_supply: Sharp SL-6000 (tosa) batteries support This patch adds common battery interface support for Sharp SL-6000 (tosa). Signed-off-by: Dmitry Baryshkov Signed-off-by: Anton Vorontsov --- drivers/power/Kconfig | 7 + drivers/power/Makefile | 1 + drivers/power/tosa_battery.c | 486 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 494 insertions(+) create mode 100644 drivers/power/tosa_battery.c (limited to 'drivers') diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 58c806e9c58..e3a9c37d08f 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -49,4 +49,11 @@ config BATTERY_OLPC help Say Y to enable support for the battery on the OLPC laptop. +config BATTERY_TOSA + tristate "Sharp SL-6000 (tosa) battery" + depends on MACH_TOSA && MFD_TC6393XB + help + Say Y to enable support for the battery on the Sharp Zaurus + SL-6000 (tosa) models. + endif # POWER_SUPPLY diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 6413ded5fe5..1e408fa268c 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -20,3 +20,4 @@ obj-$(CONFIG_APM_POWER) += apm_power.o obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o +obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c new file mode 100644 index 00000000000..bf664fbd661 --- /dev/null +++ b/drivers/power/tosa_battery.c @@ -0,0 +1,486 @@ +/* + * Battery and Power Management code for the Sharp SL-6000x + * + * Copyright (c) 2005 Dirk Opfer + * Copyright (c) 2008 Dmitry Baryshkov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static DEFINE_MUTEX(bat_lock); /* protects gpio pins */ +static struct work_struct bat_work; + +struct tosa_bat { + int status; + struct power_supply psy; + int full_chrg; + + struct mutex work_lock; /* protects data */ + + bool (*is_present)(struct tosa_bat *bat); + int gpio_full; + int gpio_charge_off; + + int technology; + + int gpio_bat; + int adc_bat; + int adc_bat_divider; + int bat_max; + int bat_min; + + int gpio_temp; + int adc_temp; + int adc_temp_divider; +}; + +static struct tosa_bat tosa_bat_main; +static struct tosa_bat tosa_bat_jacket; + +static unsigned long tosa_read_bat(struct tosa_bat *bat) +{ + unsigned long value = 0; + + if (bat->gpio_bat < 0 || bat->adc_bat < 0) + return 0; + + mutex_lock(&bat_lock); + gpio_set_value(bat->gpio_bat, 1); + msleep(5); + value = wm97xx_read_aux_adc(bat->psy.dev->parent->driver_data, + bat->adc_bat); + gpio_set_value(bat->gpio_bat, 0); + mutex_unlock(&bat_lock); + + value = value * 1000000 / bat->adc_bat_divider; + + return value; +} + +static unsigned long tosa_read_temp(struct tosa_bat *bat) +{ + unsigned long value = 0; + + if (bat->gpio_temp < 0 || bat->adc_temp < 0) + return 0; + + mutex_lock(&bat_lock); + gpio_set_value(bat->gpio_temp, 1); + msleep(5); + value = wm97xx_read_aux_adc(bat->psy.dev->parent->driver_data, + bat->adc_temp); + gpio_set_value(bat->gpio_temp, 0); + mutex_unlock(&bat_lock); + + value = value * 10000 / bat->adc_temp_divider; + + return value; +} + +static int tosa_bat_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int ret = 0; + struct tosa_bat *bat = container_of(psy, struct tosa_bat, psy); + + if (bat->is_present && !bat->is_present(bat) + && psp != POWER_SUPPLY_PROP_PRESENT) { + return -ENODEV; + } + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = bat->status; + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = bat->technology; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = tosa_read_bat(bat); + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + if (bat->full_chrg == -1) + val->intval = bat->bat_max; + else + val->intval = bat->full_chrg; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = bat->bat_max; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = bat->bat_min; + break; + case POWER_SUPPLY_PROP_TEMP: + val->intval = tosa_read_temp(bat); + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = bat->is_present ? bat->is_present(bat) : 1; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static bool tosa_jacket_bat_is_present(struct tosa_bat *bat) +{ + return gpio_get_value(TOSA_GPIO_JACKET_DETECT) == 0; +} + +static void tosa_bat_external_power_changed(struct power_supply *psy) +{ + schedule_work(&bat_work); +} + +static irqreturn_t tosa_bat_gpio_isr(int irq, void *data) +{ + pr_info("tosa_bat_gpio irq: %d\n", gpio_get_value(irq_to_gpio(irq))); + schedule_work(&bat_work); + return IRQ_HANDLED; +} + +static void tosa_bat_update(struct tosa_bat *bat) +{ + int old; + struct power_supply *psy = &bat->psy; + + mutex_lock(&bat->work_lock); + + old = bat->status; + + if (bat->is_present && !bat->is_present(bat)) { + printk(KERN_NOTICE "%s not present\n", psy->name); + bat->status = POWER_SUPPLY_STATUS_UNKNOWN; + bat->full_chrg = -1; + } else if (power_supply_am_i_supplied(psy)) { + if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING) { + gpio_set_value(bat->gpio_charge_off, 0); + mdelay(15); + } + + if (gpio_get_value(bat->gpio_full)) { + if (old == POWER_SUPPLY_STATUS_CHARGING || + bat->full_chrg == -1) + bat->full_chrg = tosa_read_bat(bat); + + gpio_set_value(bat->gpio_charge_off, 1); + bat->status = POWER_SUPPLY_STATUS_FULL; + } else { + gpio_set_value(bat->gpio_charge_off, 0); + bat->status = POWER_SUPPLY_STATUS_CHARGING; + } + } else { + gpio_set_value(bat->gpio_charge_off, 1); + bat->status = POWER_SUPPLY_STATUS_DISCHARGING; + } + + if (old != bat->status) + power_supply_changed(psy); + + mutex_unlock(&bat->work_lock); +} + +static void tosa_bat_work(struct work_struct *work) +{ + tosa_bat_update(&tosa_bat_main); + tosa_bat_update(&tosa_bat_jacket); +} + + +static enum power_supply_property tosa_bat_main_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_PRESENT, +}; + +static enum power_supply_property tosa_bat_bu_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, + POWER_SUPPLY_PROP_PRESENT, +}; + +static struct tosa_bat tosa_bat_main = { + .status = POWER_SUPPLY_STATUS_DISCHARGING, + .full_chrg = -1, + .psy = { + .name = "main-battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = tosa_bat_main_props, + .num_properties = ARRAY_SIZE(tosa_bat_main_props), + .get_property = tosa_bat_get_property, + .external_power_changed = tosa_bat_external_power_changed, + .use_for_apm = 1, + }, + + .gpio_full = TOSA_GPIO_BAT0_CRG, + .gpio_charge_off = TOSA_GPIO_CHARGE_OFF, + + .technology = POWER_SUPPLY_TECHNOLOGY_LIPO, + + .gpio_bat = TOSA_GPIO_BAT0_V_ON, + .adc_bat = WM97XX_AUX_ID3, + .adc_bat_divider = 414, + .bat_max = 4310000, + .bat_min = 1551 * 1000000 / 414, + + .gpio_temp = TOSA_GPIO_BAT1_TH_ON, + .adc_temp = WM97XX_AUX_ID2, + .adc_temp_divider = 10000, +}; + +static struct tosa_bat tosa_bat_jacket = { + .status = POWER_SUPPLY_STATUS_DISCHARGING, + .full_chrg = -1, + .psy = { + .name = "jacket-battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = tosa_bat_main_props, + .num_properties = ARRAY_SIZE(tosa_bat_main_props), + .get_property = tosa_bat_get_property, + .external_power_changed = tosa_bat_external_power_changed, + }, + + .is_present = tosa_jacket_bat_is_present, + .gpio_full = TOSA_GPIO_BAT1_CRG, + .gpio_charge_off = TOSA_GPIO_CHARGE_OFF_JC, + + .technology = POWER_SUPPLY_TECHNOLOGY_LIPO, + + .gpio_bat = TOSA_GPIO_BAT1_V_ON, + .adc_bat = WM97XX_AUX_ID3, + .adc_bat_divider = 414, + .bat_max = 4310000, + .bat_min = 1551 * 1000000 / 414, + + .gpio_temp = TOSA_GPIO_BAT0_TH_ON, + .adc_temp = WM97XX_AUX_ID2, + .adc_temp_divider = 10000, +}; + +static struct tosa_bat tosa_bat_bu = { + .status = POWER_SUPPLY_STATUS_UNKNOWN, + .full_chrg = -1, + + .psy = { + .name = "backup-battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = tosa_bat_bu_props, + .num_properties = ARRAY_SIZE(tosa_bat_bu_props), + .get_property = tosa_bat_get_property, + .external_power_changed = tosa_bat_external_power_changed, + }, + + .gpio_full = -1, + .gpio_charge_off = -1, + + .technology = POWER_SUPPLY_TECHNOLOGY_LiMn, + + .gpio_bat = TOSA_GPIO_BU_CHRG_ON, + .adc_bat = WM97XX_AUX_ID4, + .adc_bat_divider = 1266, + + .gpio_temp = -1, + .adc_temp = -1, + .adc_temp_divider = -1, +}; + +static struct { + int gpio; + char *name; + bool output; + int value; +} gpios[] = { + { TOSA_GPIO_CHARGE_OFF, "main charge off", 1, 1 }, + { TOSA_GPIO_CHARGE_OFF_JC, "jacket charge off", 1, 1 }, + { TOSA_GPIO_BAT_SW_ON, "battery switch", 1, 0 }, + { TOSA_GPIO_BAT0_V_ON, "main battery", 1, 0 }, + { TOSA_GPIO_BAT1_V_ON, "jacket battery", 1, 0 }, + { TOSA_GPIO_BAT1_TH_ON, "main battery temp", 1, 0 }, + { TOSA_GPIO_BAT0_TH_ON, "jacket battery temp", 1, 0 }, + { TOSA_GPIO_BU_CHRG_ON, "backup battery", 1, 0 }, + { TOSA_GPIO_BAT0_CRG, "main battery full", 0, 0 }, + { TOSA_GPIO_BAT1_CRG, "jacket battery full", 0, 0 }, + { TOSA_GPIO_BAT0_LOW, "main battery low", 0, 0 }, + { TOSA_GPIO_BAT1_LOW, "jacket battery low", 0, 0 }, + { TOSA_GPIO_JACKET_DETECT, "jacket detect", 0, 0 }, +}; + +#ifdef CONFIG_PM +static int tosa_bat_suspend(struct platform_device *dev, pm_message_t state) +{ + /* flush all pending status updates */ + flush_scheduled_work(); + return 0; +} + +static int tosa_bat_resume(struct platform_device *dev) +{ + /* things may have changed while we were away */ + schedule_work(&bat_work); + return 0; +} +#else +#define tosa_bat_suspend NULL +#define tosa_bat_resume NULL +#endif + +static int __devinit tosa_bat_probe(struct platform_device *dev) +{ + int ret; + int i; + + if (!machine_is_tosa()) + return -ENODEV; + + for (i = 0; i < ARRAY_SIZE(gpios); i++) { + ret = gpio_request(gpios[i].gpio, gpios[i].name); + if (ret) { + i--; + goto err_gpio; + } + + if (gpios[i].output) + ret = gpio_direction_output(gpios[i].gpio, + gpios[i].value); + else + ret = gpio_direction_input(gpios[i].gpio); + + if (ret) + goto err_gpio; + } + + mutex_init(&tosa_bat_main.work_lock); + mutex_init(&tosa_bat_jacket.work_lock); + + INIT_WORK(&bat_work, tosa_bat_work); + + ret = power_supply_register(&dev->dev, &tosa_bat_main.psy); + if (ret) + goto err_psy_reg_main; + ret = power_supply_register(&dev->dev, &tosa_bat_jacket.psy); + if (ret) + goto err_psy_reg_jacket; + ret = power_supply_register(&dev->dev, &tosa_bat_bu.psy); + if (ret) + goto err_psy_reg_bu; + + ret = request_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG), + tosa_bat_gpio_isr, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "main full", &tosa_bat_main); + if (ret) + goto err_req_main; + + ret = request_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG), + tosa_bat_gpio_isr, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "jacket full", &tosa_bat_jacket); + if (ret) + goto err_req_jacket; + + ret = request_irq(gpio_to_irq(TOSA_GPIO_JACKET_DETECT), + tosa_bat_gpio_isr, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "jacket detect", &tosa_bat_jacket); + if (!ret) { + schedule_work(&bat_work); + return 0; + } + + free_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG), &tosa_bat_jacket); +err_req_jacket: + free_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG), &tosa_bat_main); +err_req_main: + power_supply_unregister(&tosa_bat_bu.psy); +err_psy_reg_bu: + power_supply_unregister(&tosa_bat_jacket.psy); +err_psy_reg_jacket: + power_supply_unregister(&tosa_bat_main.psy); +err_psy_reg_main: + + /* see comment in tosa_bat_remove */ + flush_scheduled_work(); + + i--; +err_gpio: + for (; i >= 0; i--) + gpio_free(gpios[i].gpio); + + return ret; +} + +static int __devexit tosa_bat_remove(struct platform_device *dev) +{ + int i; + + free_irq(gpio_to_irq(TOSA_GPIO_JACKET_DETECT), &tosa_bat_jacket); + free_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG), &tosa_bat_jacket); + free_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG), &tosa_bat_main); + + power_supply_unregister(&tosa_bat_bu.psy); + power_supply_unregister(&tosa_bat_jacket.psy); + power_supply_unregister(&tosa_bat_main.psy); + + /* + * now flush all pending work. + * we won't get any more schedules, since all + * sources (isr and external_power_changed) + * are unregistered now. + */ + flush_scheduled_work(); + + for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--) + gpio_free(gpios[i].gpio); + + return 0; +} + +static struct platform_driver tosa_bat_driver = { + .driver.name = "wm97xx-battery", + .driver.owner = THIS_MODULE, + .probe = tosa_bat_probe, + .remove = __devexit_p(tosa_bat_remove), + .suspend = tosa_bat_suspend, + .resume = tosa_bat_resume, +}; + +static int __init tosa_bat_init(void) +{ + return platform_driver_register(&tosa_bat_driver); +} + +static void __exit tosa_bat_exit(void) +{ + platform_driver_unregister(&tosa_bat_driver); +} + +module_init(tosa_bat_init); +module_exit(tosa_bat_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Dmitry Baryshkov"); +MODULE_DESCRIPTION("Tosa battery driver"); +MODULE_ALIAS("platform:wm97xx-battery"); -- cgit v1.2.3 From 89f9257c06cb635ef140bd1acf21fb067ed4ed34 Mon Sep 17 00:00:00 2001 From: Henk Vergonet Date: Thu, 9 Aug 2007 11:02:30 -0300 Subject: V4L/DVB (7736): This patch adds support for the Micronas DRX3975D/DRX3977D DVB-T demodulator The module needs an external firmware file. The module has been tested on a Pinnacle 330e, but with modules that are currently not part of the linux-dvb tree. So consider this highly experimental, don't use this code unless you are an experienced kernel developer. create mode 100644 drivers/media/dvb/frontends/drx397xD.c create mode 100644 drivers/media/dvb/frontends/drx397xD.h create mode 100644 drivers/media/dvb/frontends/drx397xD_fw.h Signed-off-by: Henk Vergonet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 14 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/drx397xD.c | 1505 +++++++++++++++++++++++++++++ drivers/media/dvb/frontends/drx397xD.h | 130 +++ drivers/media/dvb/frontends/drx397xD_fw.h | 40 + 5 files changed, 1690 insertions(+) create mode 100644 drivers/media/dvb/frontends/drx397xD.c create mode 100644 drivers/media/dvb/frontends/drx397xD.h create mode 100644 drivers/media/dvb/frontends/drx397xD_fw.h (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index c20553c4da1..fa7f0c56377 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -135,6 +135,20 @@ config DVB_CX22702 help A DVB-T tuner module. Say Y when you want to support this frontend. +config DVB_DRX397XD + tristate "Micronas DRX3975D/DRX3977D based" + depends on DVB_CORE && I2C && HOTPLUG + default m if DVB_FE_CUSTOMISE + select FW_LOADER + help + A DVB-T tuner module. Say Y when you want to support this frontend. + + TODO: + This driver needs external firmware. Please use the command + "/Documentation/dvb/get_dvb_firmware drx397xD" to + download/extract them, and then copy them to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + config DVB_L64781 tristate "LSI L64781" depends on DVB_CORE && I2C diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index a89dc0fc4c6..028da55611c 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_DVB_NXT6000) += nxt6000.o obj-$(CONFIG_DVB_MT352) += mt352.o obj-$(CONFIG_DVB_ZL10353) += zl10353.o obj-$(CONFIG_DVB_CX22702) += cx22702.o +obj-$(CONFIG_DVB_DRX397XD) += drx397xD.o obj-$(CONFIG_DVB_TDA10021) += tda10021.o obj-$(CONFIG_DVB_TDA10023) += tda10023.o obj-$(CONFIG_DVB_STV0297) += stv0297.o diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c new file mode 100644 index 00000000000..b0ff77ffc88 --- /dev/null +++ b/drivers/media/dvb/frontends/drx397xD.c @@ -0,0 +1,1505 @@ +/* + * Driver for Micronas drx397xD demodulator + * + * Copyright (C) 2007 Henk Vergonet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see . + */ + +#define DEBUG /* uncomment if you want debugging output */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "drx397xD.h" + +static const char mod_name[] = "drx397xD"; + +#define MAX_CLOCK_DRIFT 200 /* maximal 200 PPM allowed */ + +#define F_SET_0D0h 1 +#define F_SET_0D4h 2 + +typedef enum fw_ix { +#define _FW_ENTRY(a, b) b +#include "drx397xD_fw.h" +} fw_ix_t; + +/* chip specifics */ +struct drx397xD_state { + struct i2c_adapter *i2c; + struct dvb_frontend frontend; + struct drx397xD_config config; + fw_ix_t chip_rev; + int flags; + u32 bandwidth_parm; /* internal bandwidth conversions */ + u32 f_osc; /* w90: actual osc frequency [Hz] */ +}; + +/******************************************************************************* + * Firmware + ******************************************************************************/ + +static const char *blob_name[] = { +#define _BLOB_ENTRY(a, b) a +#include "drx397xD_fw.h" +}; + +typedef enum blob_ix { +#define _BLOB_ENTRY(a, b) b +#include "drx397xD_fw.h" +} blob_ix_t; + +static struct { + const char *name; + const struct firmware *file; + rwlock_t lock; + int refcnt; + u8 *data[ARRAY_SIZE(blob_name)]; +} fw[] = { +#define _FW_ENTRY(a, b) { \ + .name = a, \ + .file = 0, \ + .lock = RW_LOCK_UNLOCKED, \ + .refcnt = 0, \ + .data = { } } +#include "drx397xD_fw.h" +}; + +/* use only with writer lock aquired */ +static void _drx_release_fw(struct drx397xD_state *s, fw_ix_t ix) +{ + memset(&fw[ix].data[0], 0, sizeof(fw[0].data)); + if (fw[ix].file) + release_firmware(fw[ix].file); +} + +static void drx_release_fw(struct drx397xD_state *s) +{ + fw_ix_t ix = s->chip_rev; + + pr_debug("%s\n", __FUNCTION__); + + write_lock(&fw[ix].lock); + if (fw[ix].refcnt) { + fw[ix].refcnt--; + if (fw[ix].refcnt == 0) + _drx_release_fw(s, ix); + } + write_unlock(&fw[ix].lock); +} + +static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix) +{ + u8 *data; + size_t size, len; + int i = 0, j, rc = -EINVAL; + + pr_debug("%s\n", __FUNCTION__); + + if (ix < 0 || ix >= ARRAY_SIZE(fw)) + return -EINVAL; + s->chip_rev = ix; + + write_lock(&fw[ix].lock); + if (fw[ix].file) { + rc = 0; + goto exit_ok; + } + memset(&fw[ix].data[0], 0, sizeof(fw[0].data)); + + if (request_firmware(&fw[ix].file, fw[ix].name, &s->i2c->dev) != 0) { + printk(KERN_ERR "%s: Firmware \"%s\" not available\n", + mod_name, fw[ix].name); + rc = -ENOENT; + goto exit_err; + } + + if (!fw[ix].file->data || fw[ix].file->size < 10) + goto exit_corrupt; + + data = fw[ix].file->data; + size = fw[ix].file->size; + + if (data[i++] != 2) /* check firmware version */ + goto exit_corrupt; + + do { + switch (data[i++]) { + case 0x00: /* bytecode */ + if (i >= size) + break; + i += data[i]; + case 0x01: /* reset */ + case 0x02: /* sleep */ + i++; + break; + case 0xfe: /* name */ + len = strnlen(&data[i], size - i); + if (i + len + 1 >= size) + goto exit_corrupt; + if (data[i + len + 1] != 0) + goto exit_corrupt; + for (j = 0; j < ARRAY_SIZE(blob_name); j++) { + if (strcmp(blob_name[j], &data[i]) == 0) { + fw[ix].data[j] = &data[i + len + 1]; + pr_debug("Loading %s\n", blob_name[j]); + } + } + i += len + 1; + break; + case 0xff: /* file terminator */ + if (i == size) { + rc = 0; + goto exit_ok; + } + default: + goto exit_corrupt; + } + } while (i < size); + exit_corrupt: + printk(KERN_ERR "%s: Firmware is corrupt\n", mod_name); + exit_err: + _drx_release_fw(s, ix); + fw[ix].refcnt--; + exit_ok: + fw[ix].refcnt++; + write_unlock(&fw[ix].lock); + return rc; +} + +/******************************************************************************* + * i2c bus IO + ******************************************************************************/ + +static int write_fw(struct drx397xD_state *s, blob_ix_t ix) +{ + struct i2c_msg msg = {.addr = s->config.demod_address,.flags = 0 }; + u8 *data; + int len, rc = 0, i = 0; + + if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) { + pr_debug("%s drx_fw_ix_t out of range\n", __FUNCTION__); + return -EINVAL; + } + pr_debug("%s %s\n", __FUNCTION__, blob_name[ix]); + + read_lock(&fw[s->chip_rev].lock); + data = fw[s->chip_rev].data[ix]; + if (!data) { + rc = -EINVAL; + goto exit_rc; + } + + for (;;) { + switch (data[i++]) { + case 0: /* bytecode */ + len = data[i++]; + msg.len = len; + msg.buf = &data[i]; + if (i2c_transfer(s->i2c, &msg, 1) != 1) { + rc = -EIO; + goto exit_rc; + } + i += len; + break; + case 1: /* reset */ + case 2: /* sleep */ + i++; + break; + default: + goto exit_rc; + } + } + exit_rc: + read_unlock(&fw[s->chip_rev].lock); + return 0; +} + +/* Function is not endian safe, use the RD16 wrapper below */ +static int _read16(struct drx397xD_state *s, u32 i2c_adr) +{ + int rc; + u8 a[4]; + u16 v; + struct i2c_msg msg[2] = { + { + .addr = s->config.demod_address, + .flags = 0, + .buf = a, + .len = sizeof(a) + } + , { + .addr = s->config.demod_address, + .flags = I2C_M_RD, + .buf = (u8 *) & v, + .len = sizeof(v) + } + }; + + *(u32 *) a = i2c_adr; + + rc = i2c_transfer(s->i2c, msg, 2); + if (rc != 2) + return -EIO; + + return le16_to_cpu(v); +} + +/* Function is not endian safe, use the WR16.. wrappers below */ +static int _write16(struct drx397xD_state *s, u32 i2c_adr, u16 val) +{ + u8 a[6]; + int rc; + struct i2c_msg msg = { + .addr = s->config.demod_address, + .flags = 0, + .buf = a, + .len = sizeof(a) + }; + + *(u32 *) a = i2c_adr; + *(u16 *) & a[4] = val; + + rc = i2c_transfer(s->i2c, &msg, 1); + if (rc != 1) + return -EIO; + return 0; +} + +#define WR16(ss,adr, val) \ + _write16(ss, I2C_ADR_C0(adr), cpu_to_le16(val)) +#define WR16_E0(ss,adr, val) \ + _write16(ss, I2C_ADR_E0(adr), cpu_to_le16(val)) +#define RD16(ss,adr) \ + _read16(ss, I2C_ADR_C0(adr)) + +#define EXIT_RC( cmd ) if ( (rc = (cmd)) < 0) goto exit_rc + +/******************************************************************************* + * Tuner callback + ******************************************************************************/ + +static int PLL_Set(struct drx397xD_state *s, + struct dvb_frontend_parameters *fep, int *df_tuner) +{ + struct dvb_frontend *fe = &s->frontend; + u32 f_tuner, f = fep->frequency; + int rc; + + pr_debug("%s\n", __FUNCTION__); + + if ((f > s->frontend.ops.tuner_ops.info.frequency_max) || + (f < s->frontend.ops.tuner_ops.info.frequency_min)) + return -EINVAL; + + *df_tuner = 0; + if (!s->frontend.ops.tuner_ops.set_params || + !s->frontend.ops.tuner_ops.get_frequency) + return -ENOSYS; + + rc = s->frontend.ops.tuner_ops.set_params(fe, fep); + if (rc < 0) + return rc; + + rc = s->frontend.ops.tuner_ops.get_frequency(fe, &f_tuner); + if (rc < 0) + return rc; + + *df_tuner = f_tuner - f; + pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __FUNCTION__, f, + f_tuner); + + return 0; +} + +/******************************************************************************* + * Demodulator helper functions + ******************************************************************************/ + +static int SC_WaitForReady(struct drx397xD_state *s) +{ + int cnt = 1000; + int rc; + + pr_debug("%s\n", __FUNCTION__); + + while (cnt--) { + rc = RD16(s, 0x820043); + if (rc == 0) + return 0; + } + return -1; +} + +static int SC_SendCommand(struct drx397xD_state *s, int cmd) +{ + int rc; + + pr_debug("%s\n", __FUNCTION__); + + WR16(s, 0x820043, cmd); + SC_WaitForReady(s); + rc = RD16(s, 0x820042); + if ((rc & 0xffff) == 0xffff) + return -1; + return 0; +} + +static int HI_Command(struct drx397xD_state *s, u16 cmd) +{ + int rc, cnt = 1000; + + pr_debug("%s\n", __FUNCTION__); + + rc = WR16(s, 0x420032, cmd); + if (rc < 0) + return rc; + + do { + rc = RD16(s, 0x420032); + if (rc == 0) { + rc = RD16(s, 0x420031); + return rc; + } + if (rc < 0) + return rc; + } while (--cnt); + return rc; +} + +static int HI_CfgCommand(struct drx397xD_state *s) +{ + + pr_debug("%s\n", __FUNCTION__); + + WR16(s, 0x420033, 0x3973); + WR16(s, 0x420034, s->config.w50); // code 4, log 4 + WR16(s, 0x420035, s->config.w52); // code 15, log 9 + WR16(s, 0x420036, s->config.demod_address << 1); + WR16(s, 0x420037, s->config.w56); // code (set_i2c ?? initX 1 ), log 1 +// WR16(s, 0x420033, 0x3973); + if ((s->config.w56 & 8) == 0) + return HI_Command(s, 3); + return WR16(s, 0x420032, 0x3); +} + +static const u8 fastIncrDecLUT_15273[] = { + 0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1d, 0x1f +}; + +static const u8 slowIncrDecLUT_15272[] = { + 3, 4, 4, 5, 6 +}; + +static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc) +{ + u16 w06 = agc->w06; + u16 w08 = agc->w08; + u16 w0A = agc->w0A; + u16 w0C = agc->w0C; + int quot, rem, i, rc = -EINVAL; + + pr_debug("%s\n", __FUNCTION__); + + if (agc->w04 > 0x3ff) + goto exit_rc; + + if (agc->d00 == 1) { + EXIT_RC(RD16(s, 0x0c20010)); + rc &= ~0x10; + EXIT_RC(WR16(s, 0x0c20010, rc)); + return WR16(s, 0x0c20030, agc->w04 & 0x7ff); + } + + if (agc->d00 != 0) + goto exit_rc; + if (w0A < w08) + goto exit_rc; + if (w0A > 0x3ff) + goto exit_rc; + if (w0C > 0x3ff) + goto exit_rc; + if (w06 > 0x3ff) + goto exit_rc; + + EXIT_RC(RD16(s, 0x0c20010)); + rc |= 0x10; + EXIT_RC(WR16(s, 0x0c20010, rc)); + + EXIT_RC(WR16(s, 0x0c20025, (w06 >> 1) & 0x1ff)); + EXIT_RC(WR16(s, 0x0c20031, (w0A - w08) >> 1)); + EXIT_RC(WR16(s, 0x0c20032, ((w0A + w08) >> 1) - 0x1ff)); + + quot = w0C / 113; + rem = w0C % 113; + if (quot <= 8) { + quot = 8 - quot; + } else { + quot = 0; + rem += 113; + } + + EXIT_RC(WR16(s, 0x0c20024, quot)); + + i = fastIncrDecLUT_15273[rem / 8]; + EXIT_RC(WR16(s, 0x0c2002d, i)); + EXIT_RC(WR16(s, 0x0c2002e, i)); + + i = slowIncrDecLUT_15272[rem / 28]; + EXIT_RC(WR16(s, 0x0c2002b, i)); + rc = WR16(s, 0x0c2002c, i); + exit_rc: + return rc; +} + +static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc) +{ + u16 w04 = agc->w04; + u16 w06 = agc->w06; + int rc = -1; + + pr_debug("%s %d 0x%x 0x%x\n", __FUNCTION__, agc->d00, w04, w06); + + if (w04 > 0x3ff) + goto exit_rc; + + switch (agc->d00) { + case 1: + if (w04 == 0x3ff) + w04 = 0x400; + + EXIT_RC(WR16(s, 0x0c20036, w04)); + s->config.w9C &= ~2; + EXIT_RC(WR16(s, 0x0c20015, s->config.w9C)); + EXIT_RC(RD16(s, 0x0c20010)); + rc &= 0xbfdf; + EXIT_RC(WR16(s, 0x0c20010, rc)); + EXIT_RC(RD16(s, 0x0c20013)); + rc &= ~2; + break; + case 0: + // loc_8000659 + s->config.w9C &= ~2; + EXIT_RC(WR16(s, 0x0c20015, s->config.w9C)); + EXIT_RC(RD16(s, 0x0c20010)); + rc &= 0xbfdf; + rc |= 0x4000; + EXIT_RC(WR16(s, 0x0c20010, rc)); + EXIT_RC(WR16(s, 0x0c20051, (w06 >> 4) & 0x3f)); + EXIT_RC(RD16(s, 0x0c20013)); + rc &= ~2; + break; + default: + s->config.w9C |= 2; + EXIT_RC(WR16(s, 0x0c20015, s->config.w9C)); + EXIT_RC(RD16(s, 0x0c20010)); + rc &= 0xbfdf; + EXIT_RC(WR16(s, 0x0c20010, rc)); + + EXIT_RC(WR16(s, 0x0c20036, 0)); + + EXIT_RC(RD16(s, 0x0c20013)); + rc |= 2; + } + rc = WR16(s, 0x0c20013, rc); + exit_rc: + return rc; +} + +static int GetLockStatus(struct drx397xD_state *s, int *lockstat) +{ + int rc; + + *lockstat = 0; + + rc = RD16(s, 0x082004b); + if (rc < 0) + return rc; + + if (s->config.d60 != 2) + return 0; + + if ((rc & 7) == 7) + *lockstat |= 1; + if ((rc & 3) == 3) + *lockstat |= 2; + if (rc & 1) + *lockstat |= 4; + return 0; +} + +static int CorrectSysClockDeviation(struct drx397xD_state *s) +{ + int rc = -EINVAL; + int lockstat; + u32 clk, clk_limit; + + pr_debug("%s\n", __FUNCTION__); + + if (s->config.d5C == 0) { + EXIT_RC(WR16(s, 0x08200e8, 0x010)); + EXIT_RC(WR16(s, 0x08200e9, 0x113)); + s->config.d5C = 1; + return rc; + } + if (s->config.d5C != 1) + goto exit_rc; + + rc = RD16(s, 0x0820048); + + rc = GetLockStatus(s, &lockstat); + if (rc < 0) + goto exit_rc; + if ((lockstat & 1) == 0) + goto exit_rc; + + EXIT_RC(WR16(s, 0x0420033, 0x200)); + EXIT_RC(WR16(s, 0x0420034, 0xc5)); + EXIT_RC(WR16(s, 0x0420035, 0x10)); + EXIT_RC(WR16(s, 0x0420036, 0x1)); + EXIT_RC(WR16(s, 0x0420037, 0xa)); + EXIT_RC(HI_Command(s, 6)); + EXIT_RC(RD16(s, 0x0420040)); + clk = rc; + EXIT_RC(RD16(s, 0x0420041)); + clk |= rc << 16; + + if (clk <= 0x26ffff) + goto exit_rc; + if (clk > 0x610000) + goto exit_rc; + + if (!s->bandwidth_parm) + return -EINVAL; + + /* round & convert to Hz */ + clk = ((u64) (clk + 0x800000) * s->bandwidth_parm + (1 << 20)) >> 21; + clk_limit = s->config.f_osc * MAX_CLOCK_DRIFT / 1000; + + if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) { + s->f_osc = clk; + pr_debug("%s: osc %d %d [Hz]\n", __FUNCTION__, + s->config.f_osc * 1000, clk - s->config.f_osc * 1000); + } + rc = WR16(s, 0x08200e8, 0); + exit_rc: + return rc; +} + +static int ConfigureMPEGOutput(struct drx397xD_state *s, int type) +{ + int rc, si, bp; + + pr_debug("%s\n", __FUNCTION__); + + si = s->config.wA0; + if (s->config.w98 == 0) { + si |= 1; + bp = 0; + } else { + si &= ~1; + bp = 0x200; + } + if (s->config.w9A == 0) { + si |= 0x80; + } else { + si &= ~0x80; + } + + EXIT_RC(WR16(s, 0x2150045, 0)); + EXIT_RC(WR16(s, 0x2150010, si)); + EXIT_RC(WR16(s, 0x2150011, bp)); + rc = WR16(s, 0x2150012, (type == 0 ? 0xfff : 0)); + exit_rc: + return rc; +} + +static int drx_tune(struct drx397xD_state *s, + struct dvb_frontend_parameters *fep) +{ + u16 v22 = 0; + u16 v1C = 0; + u16 v1A = 0; + u16 v18 = 0; + u32 edi = 0, ebx = 0, ebp = 0, edx = 0; + u16 v20 = 0, v1E = 0, v16 = 0, v14 = 0, v12 = 0, v10 = 0, v0E = 0; + + int rc, df_tuner; + int a, b, c, d; + pr_debug("%s %d\n", __FUNCTION__, s->config.d60); + + if (s->config.d60 != 2) + goto set_tuner; + rc = CorrectSysClockDeviation(s); + if (rc < 0) + goto set_tuner; + + s->config.d60 = 1; + rc = ConfigureMPEGOutput(s, 0); + if (rc < 0) + goto set_tuner; + set_tuner: + + rc = PLL_Set(s, fep, &df_tuner); + if (rc < 0) { + printk(KERN_ERR "Error in pll_set\n"); + goto exit_rc; + } + msleep(200); + + a = rc = RD16(s, 0x2150016); + if (rc < 0) + goto exit_rc; + b = rc = RD16(s, 0x2150010); + if (rc < 0) + goto exit_rc; + c = rc = RD16(s, 0x2150034); + if (rc < 0) + goto exit_rc; + d = rc = RD16(s, 0x2150035); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x2150014, c); + rc = WR16(s, 0x2150015, d); + rc = WR16(s, 0x2150010, 0); + rc = WR16(s, 0x2150000, 2); + rc = WR16(s, 0x2150036, 0x0fff); + rc = WR16(s, 0x2150016, a); + + rc = WR16(s, 0x2150010, 2); + rc = WR16(s, 0x2150007, 0); + rc = WR16(s, 0x2150000, 1); + rc = WR16(s, 0x2110000, 0); + rc = WR16(s, 0x0800000, 0); + rc = WR16(s, 0x2800000, 0); + rc = WR16(s, 0x2110010, 0x664); + + rc = write_fw(s, DRXD_ResetECRAM); + rc = WR16(s, 0x2110000, 1); + + rc = write_fw(s, DRXD_InitSC); + if (rc < 0) + goto exit_rc; + + rc = SetCfgIfAgc(s, &s->config.ifagc); + if (rc < 0) + goto exit_rc; + + rc = SetCfgRfAgc(s, &s->config.rfagc); + if (rc < 0) + goto exit_rc; + + if (fep->u.ofdm.transmission_mode != TRANSMISSION_MODE_2K) + v22 = 1; + switch (fep->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: + edi = 1; + if (s->chip_rev == DRXD_FW_B1) + break; + + rc = WR16(s, 0x2010010, 0); + if (rc < 0) + break; + v1C = 0x63; + v1A = 0x53; + v18 = 0x43; + break; + default: + edi = 0; + if (s->chip_rev == DRXD_FW_B1) + break; + + rc = WR16(s, 0x2010010, 1); + if (rc < 0) + break; + + v1C = 0x61; + v1A = 0x47; + v18 = 0x41; + } + + switch (fep->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_4: + edi |= 0x0c; + break; + case GUARD_INTERVAL_1_8: + edi |= 0x08; + break; + case GUARD_INTERVAL_1_16: + edi |= 0x04; + break; + case GUARD_INTERVAL_1_32: + break; + default: + v22 |= 2; + } + + ebx = 0; + ebp = 0; + v20 = 0; + v1E = 0; + v16 = 0; + v14 = 0; + v12 = 0; + v10 = 0; + v0E = 0; + + switch (fep->u.ofdm.hierarchy_information) { + case HIERARCHY_1: + edi |= 0x40; + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x1c10047, 1); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x2010012, 1); + if (rc < 0) + goto exit_rc; + ebx = 0x19f; + ebp = 0x1fb; + v20 = 0x0c0; + v1E = 0x195; + v16 = 0x1d6; + v14 = 0x1ef; + v12 = 4; + v10 = 5; + v0E = 5; + break; + case HIERARCHY_2: + edi |= 0x80; + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x1c10047, 2); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x2010012, 2); + if (rc < 0) + goto exit_rc; + ebx = 0x08f; + ebp = 0x12f; + v20 = 0x0c0; + v1E = 0x11e; + v16 = 0x1d6; + v14 = 0x15e; + v12 = 4; + v10 = 5; + v0E = 5; + break; + case HIERARCHY_4: + edi |= 0xc0; + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x1c10047, 3); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x2010012, 3); + if (rc < 0) + goto exit_rc; + ebx = 0x14d; + ebp = 0x197; + v20 = 0x0c0; + v1E = 0x1ce; + v16 = 0x1d6; + v14 = 0x11a; + v12 = 4; + v10 = 6; + v0E = 5; + break; + default: + v22 |= 8; + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x1c10047, 0); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x2010012, 0); + if (rc < 0) + goto exit_rc; + // QPSK QAM16 QAM64 + ebx = 0x19f; // 62 + ebp = 0x1fb; // 15 + v20 = 0x16a; // 62 + v1E = 0x195; // 62 + v16 = 0x1bb; // 15 + v14 = 0x1ef; // 15 + v12 = 5; // 16 + v10 = 5; // 16 + v0E = 5; // 16 + } + + switch (fep->u.ofdm.constellation) { + default: + v22 |= 4; + case QPSK: + if (s->chip_rev == DRXD_FW_B1) + break; + + rc = WR16(s, 0x1c10046, 0); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x2010011, 0); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001a, 0x10); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001b, 0); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001c, 0); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10062, v20); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c1002a, v1C); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10015, v16); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10016, v12); + if (rc < 0) + goto exit_rc; + break; + case QAM_16: + edi |= 0x10; + if (s->chip_rev == DRXD_FW_B1) + break; + + rc = WR16(s, 0x1c10046, 1); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x2010011, 1); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001a, 0x10); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001b, 4); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001c, 0); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10062, v1E); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c1002a, v1A); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10015, v14); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10016, v10); + if (rc < 0) + goto exit_rc; + break; + case QAM_64: + edi |= 0x20; + rc = WR16(s, 0x1c10046, 2); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x2010011, 2); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001a, 0x20); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001b, 8); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x201001c, 2); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10062, ebx); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c1002a, v18); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10015, ebp); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x1c10016, v0E); + if (rc < 0) + goto exit_rc; + break; + } + + if (s->config.s20d24 == 1) { + rc = WR16(s, 0x2010013, 0); + } else { + rc = WR16(s, 0x2010013, 1); + edi |= 0x1000; + } + + switch (fep->u.ofdm.code_rate_HP) { + default: + v22 |= 0x10; + case FEC_1_2: + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x2090011, 0); + break; + case FEC_2_3: + edi |= 0x200; + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x2090011, 1); + break; + case FEC_3_4: + edi |= 0x400; + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x2090011, 2); + break; + case FEC_5_6: /* 5 */ + edi |= 0x600; + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x2090011, 3); + break; + case FEC_7_8: /* 7 */ + edi |= 0x800; + if (s->chip_rev == DRXD_FW_B1) + break; + rc = WR16(s, 0x2090011, 4); + break; + }; + if (rc < 0) + goto exit_rc; + + switch (fep->u.ofdm.bandwidth) { + default: + rc = -EINVAL; + goto exit_rc; + case BANDWIDTH_8_MHZ: /* 0 */ + case BANDWIDTH_AUTO: + rc = WR16(s, 0x0c2003f, 0x32); + s->bandwidth_parm = ebx = 0x8b8249; // 9142857 + edx = 0; + break; + case BANDWIDTH_7_MHZ: + rc = WR16(s, 0x0c2003f, 0x3b); + s->bandwidth_parm = ebx = 0x7a1200; // 8000000 + edx = 0x4807; + break; + case BANDWIDTH_6_MHZ: + rc = WR16(s, 0x0c2003f, 0x47); + s->bandwidth_parm = ebx = 0x68a1b6; // 6857142 + edx = 0x0f07; + break; + }; + + if (rc < 0) + goto exit_rc; + + rc = WR16(s, 0x08200ec, edx); + if (rc < 0) + goto exit_rc; + + rc = RD16(s, 0x0820050); + if (rc < 0) + goto exit_rc; + rc = WR16(s, 0x0820050, rc); + + { + long dummy; + + /* Configure bandwidth specific factor */ + ebx = div_ll_X_l_rem(((u64) (s->f_osc) << 21) + (ebx >> 1), + ebx, &dummy) - 0x800000; + EXIT_RC(WR16(s, 0x0c50010, ebx & 0xffff)); + EXIT_RC(WR16(s, 0x0c50011, ebx >> 16)); + + /* drx397xD oscillator calibration */ + ebx = div_ll_X_l_rem(((u64) (s->config.f_if + df_tuner) << 28) + + (s->f_osc >> 1), s->f_osc, &dummy); + } + ebx &= 0xfffffff; + if (fep->inversion == INVERSION_ON) + ebx = 0x10000000 - ebx; + + EXIT_RC(WR16(s, 0x0c30010, ebx & 0xffff)); + EXIT_RC(WR16(s, 0x0c30011, ebx >> 16)); + + EXIT_RC(WR16(s, 0x0800000, 1)); + EXIT_RC(RD16(s, 0x0800000)); + + + EXIT_RC(SC_WaitForReady(s)); + EXIT_RC(WR16(s, 0x0820042, 0)); + EXIT_RC(WR16(s, 0x0820041, v22)); + EXIT_RC(WR16(s, 0x0820040, edi)); + EXIT_RC(SC_SendCommand(s, 3)); + + rc = RD16(s, 0x0800000); + + SC_WaitForReady(s); + WR16(s, 0x0820042, 0); + WR16(s, 0x0820041, 1); + WR16(s, 0x0820040, 1); + SC_SendCommand(s, 1); + +// rc = WR16(s, 0x2150000, 1); +// if (rc < 0) goto exit_rc; + + rc = WR16(s, 0x2150000, 2); + rc = WR16(s, 0x2150016, a); + rc = WR16(s, 0x2150010, 4); + rc = WR16(s, 0x2150036, 0); + rc = WR16(s, 0x2150000, 1); + s->config.d60 = 2; + exit_rc: + return rc; +} + +/******************************************************************************* + * DVB interface + ******************************************************************************/ + +static int drx397x_init(struct dvb_frontend *fe) +{ + struct drx397xD_state *s = fe->demodulator_priv; + int rc; + + pr_debug("%s\n", __FUNCTION__); + + s->config.rfagc.d00 = 2; /* 0x7c */ + s->config.rfagc.w04 = 0; + s->config.rfagc.w06 = 0x3ff; + + s->config.ifagc.d00 = 0; /* 0x68 */ + s->config.ifagc.w04 = 0; + s->config.ifagc.w06 = 140; + s->config.ifagc.w08 = 0; + s->config.ifagc.w0A = 0x3ff; + s->config.ifagc.w0C = 0x388; + + /* for signal strenght calculations */ + s->config.ss76 = 820; + s->config.ss78 = 2200; + s->config.ss7A = 150; + + /* HI_CfgCommand */ + s->config.w50 = 4; + s->config.w52 = 9; // 0xf; + + s->config.f_if = 42800000; /* d14: intermediate frequency [Hz] */ + s->config.f_osc = 48000; /* s66 : oscillator frequency [kHz] */ + s->config.w92 = 12000; // 20000; + + s->config.w9C = 0x000e; + s->config.w9E = 0x0000; + + /* ConfigureMPEGOutput params */ + s->config.wA0 = 4; + s->config.w98 = 1; // 0; + s->config.w9A = 1; + + /* get chip revision */ + rc = RD16(s, 0x2410019); + if (rc < 0) + return -ENODEV; + + if (rc == 0) { + printk(KERN_INFO "%s: chip revision A2\n", mod_name); + rc = drx_load_fw(s, DRXD_FW_A2); + } else { + + rc = (rc >> 12) - 3; + switch (rc) { + case 1: + s->flags |= F_SET_0D4h; + case 0: + case 4: + s->flags |= F_SET_0D0h; + break; + case 2: + case 5: + break; + case 3: + s->flags |= F_SET_0D4h; + break; + default: + return -ENODEV; + }; + printk(KERN_INFO "%s: chip revision B1.%d\n", mod_name, rc); + rc = drx_load_fw(s, DRXD_FW_B1); + } + if (rc < 0) + goto error; + + rc = WR16(s, 0x0420033, 0x3973); + if (rc < 0) + goto error; + + rc = HI_Command(s, 2); + + msleep(1); + + if (s->chip_rev == DRXD_FW_A2) { + rc = WR16(s, 0x043012d, 0x47F); + if (rc < 0) + goto error; + } + rc = WR16_E0(s, 0x0400000, 0); + if (rc < 0) + goto error; + + if (s->config.w92 > 20000 || s->config.w92 % 4000) { + printk(KERN_ERR "%s: invalid osc frequency\n", mod_name); + rc = -1; + goto error; + } + + rc = WR16(s, 0x2410010, 1); + if (rc < 0) + goto error; + rc = WR16(s, 0x2410011, 0x15); + if (rc < 0) + goto error; + rc = WR16(s, 0x2410012, s->config.w92 / 4000); + if (rc < 0) + goto error; +#ifdef ORIG_FW + rc = WR16(s, 0x2410015, 2); + if (rc < 0) + goto error; +#endif + rc = WR16(s, 0x2410017, 0x3973); + if (rc < 0) + goto error; + + s->f_osc = s->config.f_osc * 1000; /* initial estimator */ + + s->config.w56 = 1; + + rc = HI_CfgCommand(s); + if (rc < 0) + goto error; + + rc = write_fw(s, DRXD_InitAtomicRead); + if (rc < 0) + goto error; + + if (s->chip_rev == DRXD_FW_A2) { + rc = WR16(s, 0x2150013, 0); + if (rc < 0) + goto error; + } + + rc = WR16_E0(s, 0x0400002, 0); + if (rc < 0) + goto error; + rc = WR16(s, 0x0400002, 0); + if (rc < 0) + goto error; + + if (s->chip_rev == DRXD_FW_A2) { + rc = write_fw(s, DRXD_ResetCEFR); + if (rc < 0) + goto error; + } + rc = write_fw(s, DRXD_microcode); + if (rc < 0) + goto error; + + s->config.w9C = 0x0e; + if (s->flags & F_SET_0D0h) { + s->config.w9C = 0; + rc = RD16(s, 0x0c20010); + if (rc < 0) + goto write_DRXD_InitFE_1; + + rc &= ~0x1000; + rc = WR16(s, 0x0c20010, rc); + if (rc < 0) + goto write_DRXD_InitFE_1; + + rc = RD16(s, 0x0c20011); + if (rc < 0) + goto write_DRXD_InitFE_1; + + rc &= ~0x8; + rc = WR16(s, 0x0c20011, rc); + if (rc < 0) + goto write_DRXD_InitFE_1; + + rc = WR16(s, 0x0c20012, 1); + } + + write_DRXD_InitFE_1: + + rc = write_fw(s, DRXD_InitFE_1); + if (rc < 0) + goto error; + + rc = 1; + if (s->chip_rev == DRXD_FW_B1) { + if (s->flags & F_SET_0D0h) + rc = 0; + } else { + if (s->flags & F_SET_0D0h) + rc = 4; + } + + rc = WR16(s, 0x0C20012, rc); + if (rc < 0) + goto error; + + rc = WR16(s, 0x0C20013, s->config.w9E); + if (rc < 0) + goto error; + rc = WR16(s, 0x0C20015, s->config.w9C); + if (rc < 0) + goto error; + + rc = write_fw(s, DRXD_InitFE_2); + if (rc < 0) + goto error; + rc = write_fw(s, DRXD_InitFT); + if (rc < 0) + goto error; + rc = write_fw(s, DRXD_InitCP); + if (rc < 0) + goto error; + rc = write_fw(s, DRXD_InitCE); + if (rc < 0) + goto error; + rc = write_fw(s, DRXD_InitEQ); + if (rc < 0) + goto error; + rc = write_fw(s, DRXD_InitEC); + if (rc < 0) + goto error; + rc = write_fw(s, DRXD_InitSC); + if (rc < 0) + goto error; + + rc = SetCfgIfAgc(s, &s->config.ifagc); + if (rc < 0) + goto error; + + rc = SetCfgRfAgc(s, &s->config.rfagc); + if (rc < 0) + goto error; + + rc = ConfigureMPEGOutput(s, 1); + rc = WR16(s, 0x08201fe, 0x0017); + rc = WR16(s, 0x08201ff, 0x0101); + + s->config.d5C = 0; + s->config.d60 = 1; + s->config.d48 = 1; + error: + return rc; +} + +static int drx397x_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + return 0; +} + +static int drx397x_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct drx397xD_state *s = fe->demodulator_priv; + + s->config.s20d24 = 1; // 0; + return drx_tune(s, params); +} + +static int drx397x_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings + *fe_tune_settings) +{ + fe_tune_settings->min_delay_ms = 10000; + fe_tune_settings->step_size = 0; + fe_tune_settings->max_drift = 0; + return 0; +} + +static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status) +{ + struct drx397xD_state *s = fe->demodulator_priv; + int lockstat; + + GetLockStatus(s, &lockstat); + /* TODO */ +// if (lockstat & 1) +// CorrectSysClockDeviation(s); + + *status = 0; + if (lockstat & 2) { + CorrectSysClockDeviation(s); + ConfigureMPEGOutput(s, 1); + *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI; + } + if (lockstat & 4) { + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + } + + return 0; +} + +static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber) +{ + *ber = 0; + return 0; +} + +static int drx397x_read_snr(struct dvb_frontend *fe, u16 * snr) +{ + *snr = 0; + return 0; +} + +static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 * strength) +{ + struct drx397xD_state *s = fe->demodulator_priv; + int rc; + + if (s->config.ifagc.d00 == 2) { + *strength = 0xffff; + return 0; + } + rc = RD16(s, 0x0c20035); + if (rc < 0) { + *strength = 0; + return 0; + } + rc &= 0x3ff; + /* Signal strength is calculated using the following formula: + * + * a = 2200 * 150 / (2200 + 150); + * a = a * 3300 / (a + 820); + * b = 2200 * 3300 / (2200 + 820); + * c = (((b-a) * rc) >> 10 + a) << 4; + * strength = ~c & 0xffff; + * + * The following does the same but with less rounding errors: + */ + *strength = ~(7720 + (rc * 30744 >> 10)); + return 0; +} + +static int drx397x_read_ucblocks(struct dvb_frontend *fe, + unsigned int *ucblocks) +{ + *ucblocks = 0; + return 0; +} + +static int drx397x_sleep(struct dvb_frontend *fe) +{ + return 0; +} + +static void drx397x_release(struct dvb_frontend *fe) +{ + struct drx397xD_state *s = fe->demodulator_priv; + printk(KERN_INFO "%s: release demodulator\n", mod_name); + if (s) { + drx_release_fw(s); + kfree(s); + } + +} + +static struct dvb_frontend_ops drx397x_ops = { + + .info = { + .name = "Micronas DRX397xD DVB-T Frontend", + .type = FE_OFDM, + .frequency_min = 47125000, + .frequency_max = 855250000, + .frequency_stepsize = 166667, + .frequency_tolerance = 0, + .caps = /* 0x0C01B2EAE */ + FE_CAN_FEC_1_2 | // = 0x2, + FE_CAN_FEC_2_3 | // = 0x4, + FE_CAN_FEC_3_4 | // = 0x8, + FE_CAN_FEC_5_6 | // = 0x20, + FE_CAN_FEC_7_8 | // = 0x80, + FE_CAN_FEC_AUTO | // = 0x200, + FE_CAN_QPSK | // = 0x400, + FE_CAN_QAM_16 | // = 0x800, + FE_CAN_QAM_64 | // = 0x2000, + FE_CAN_QAM_AUTO | // = 0x10000, + FE_CAN_TRANSMISSION_MODE_AUTO | // = 0x20000, + FE_CAN_GUARD_INTERVAL_AUTO | // = 0x80000, + FE_CAN_HIERARCHY_AUTO | // = 0x100000, + FE_CAN_RECOVER | // = 0x40000000, + FE_CAN_MUTE_TS // = 0x80000000 + }, + + .release = drx397x_release, + .init = drx397x_init, + .sleep = drx397x_sleep, + + .set_frontend = drx397x_set_frontend, + .get_tune_settings = drx397x_get_tune_settings, + .get_frontend = drx397x_get_frontend, + + .read_status = drx397x_read_status, + .read_snr = drx397x_read_snr, + .read_signal_strength = drx397x_read_signal_strength, + .read_ber = drx397x_read_ber, + .read_ucblocks = drx397x_read_ucblocks, +}; + +struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config, + struct i2c_adapter *i2c) +{ + struct drx397xD_state *s = NULL; + + /* allocate memory for the internal state */ + s = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL); + if (s == NULL) + goto error; + + /* setup the state */ + s->i2c = i2c; + memcpy(&s->config, config, sizeof(struct drx397xD_config)); + + /* check if the demod is there */ + if (RD16(s, 0x2410019) < 0) + goto error; + + /* create dvb_frontend */ + memcpy(&s->frontend.ops, &drx397x_ops, sizeof(struct dvb_frontend_ops)); + s->frontend.demodulator_priv = s; + + return &s->frontend; + error: + kfree(s); + return NULL; +} + +MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend"); +MODULE_AUTHOR("Henk Vergonet"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(drx397xD_attach); diff --git a/drivers/media/dvb/frontends/drx397xD.h b/drivers/media/dvb/frontends/drx397xD.h new file mode 100644 index 00000000000..ddc7a07971b --- /dev/null +++ b/drivers/media/dvb/frontends/drx397xD.h @@ -0,0 +1,130 @@ +/* + * Driver for Micronas DVB-T drx397xD demodulator + * + * Copyright (C) 2007 Henk vergonet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#ifndef _DRX397XD_H_INCLUDED +#define _DRX397XD_H_INCLUDED + +#include + +#define DRX_F_STEPSIZE 166667 +#define DRX_F_OFFSET 36000000 + +#define I2C_ADR_C0(x) \ +( (u32)cpu_to_le32( \ + (u32)( \ + (((u32)(x) & (u32)0x000000ffUL) ) | \ + (((u32)(x) & (u32)0x0000ff00UL) << 16) | \ + (((u32)(x) & (u32)0x0fff0000UL) >> 8) | \ + ( (u32)0x00c00000UL) \ + )) \ +) + +#define I2C_ADR_E0(x) \ +( (u32)cpu_to_le32( \ + (u32)( \ + (((u32)(x) & (u32)0x000000ffUL) ) | \ + (((u32)(x) & (u32)0x0000ff00UL) << 16) | \ + (((u32)(x) & (u32)0x0fff0000UL) >> 8) | \ + ( (u32)0x00e00000UL) \ + )) \ +) + +struct drx397xD_CfgRfAgc /* 0x7c */ +{ + int d00; /* 2 */ + u16 w04; + u16 w06; +}; + +struct drx397xD_CfgIfAgc /* 0x68 */ +{ + int d00; /* 0 */ + u16 w04; /* 0 */ + u16 w06; + u16 w08; + u16 w0A; + u16 w0C; +}; + +struct drx397xD_s20 { + int d04; + u32 d18; + u32 d1C; + u32 d20; + u32 d14; + u32 d24; + u32 d0C; + u32 d08; +}; + +struct drx397xD_config +{ + /* demodulator's I2C address */ + u8 demod_address; /* 0x0f */ + + struct drx397xD_CfgIfAgc ifagc; /* 0x68 */ + struct drx397xD_CfgRfAgc rfagc; /* 0x7c */ + u32 s20d24; + + /* HI_CfgCommand parameters */ + u16 w50, w52, /* w54, */ w56; + + int d5C; + int d60; + int d48; + int d28; + + u32 f_if; /* d14: intermediate frequency [Hz] */ + /* 36000000 on Cinergy 2400i DT */ + /* 42800000 on Pinnacle Hybrid PRO 330e */ + + u16 f_osc; /* s66: 48000 oscillator frequency [kHz] */ + + u16 w92; /* 20000 */ + + u16 wA0; + u16 w98; + u16 w9A; + + u16 w9C; /* 0xe0 */ + u16 w9E; /* 0x00 */ + + /* used for signal strength calculations in + drx397x_read_signal_strength + */ + u16 ss78; // 2200 + u16 ss7A; // 150 + u16 ss76; // 820 +}; + +#if defined(CONFIG_DVB_DRX397XD) || (defined(CONFIG_DVB_DRX397XD_MODULE) && defined(MODULE)) +extern struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif /* CONFIG_DVB_DRX397XD */ + +#endif /* _DRX397XD_H_INCLUDED */ diff --git a/drivers/media/dvb/frontends/drx397xD_fw.h b/drivers/media/dvb/frontends/drx397xD_fw.h new file mode 100644 index 00000000000..01de02a81cd --- /dev/null +++ b/drivers/media/dvb/frontends/drx397xD_fw.h @@ -0,0 +1,40 @@ +/* + * Firmware definitions for Micronas drx397xD + * + * Copyright (C) 2007 Henk Vergonet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see . + */ + +#ifdef _FW_ENTRY + _FW_ENTRY("drx397xD.A2.fw", DRXD_FW_A2 = 0 ), + _FW_ENTRY("drx397xD.B1.fw", DRXD_FW_B1 ), +#undef _FW_ENTRY +#endif /* _FW_ENTRY */ + +#ifdef _BLOB_ENTRY + _BLOB_ENTRY("InitAtomicRead", DRXD_InitAtomicRead = 0 ), + _BLOB_ENTRY("InitCE", DRXD_InitCE ), + _BLOB_ENTRY("InitCP", DRXD_InitCP ), + _BLOB_ENTRY("InitEC", DRXD_InitEC ), + _BLOB_ENTRY("InitEQ", DRXD_InitEQ ), + _BLOB_ENTRY("InitFE_1", DRXD_InitFE_1 ), + _BLOB_ENTRY("InitFE_2", DRXD_InitFE_2 ), + _BLOB_ENTRY("InitFT", DRXD_InitFT ), + _BLOB_ENTRY("InitSC", DRXD_InitSC ), + _BLOB_ENTRY("ResetCEFR", DRXD_ResetCEFR ), + _BLOB_ENTRY("ResetECRAM", DRXD_ResetECRAM ), + _BLOB_ENTRY("microcode", DRXD_microcode ), +#undef _BLOB_ENTRY +#endif /* _BLOB_ENTRY */ -- cgit v1.2.3 From 29e031d5b09ae60d0ecdb6a1d869d591d63e893a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 24 Apr 2008 21:43:23 -0300 Subject: V4L/DVB (7737): drx397xD: fix math usage The previous code were using a div64 math specific to i386. Replace for an asm-generic one. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/drx397xD.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c index b0ff77ffc88..af435466212 100644 --- a/drivers/media/dvb/frontends/drx397xD.c +++ b/drivers/media/dvb/frontends/drx397xD.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "dvb_frontend.h" #include "drx397xD.h" @@ -1024,17 +1025,15 @@ static int drx_tune(struct drx397xD_state *s, rc = WR16(s, 0x0820050, rc); { - long dummy; - /* Configure bandwidth specific factor */ - ebx = div_ll_X_l_rem(((u64) (s->f_osc) << 21) + (ebx >> 1), - ebx, &dummy) - 0x800000; + ebx = div64_64(((u64) (s->f_osc) << 21) + (ebx >> 1), + (u64)ebx) - 0x800000; EXIT_RC(WR16(s, 0x0c50010, ebx & 0xffff)); EXIT_RC(WR16(s, 0x0c50011, ebx >> 16)); /* drx397xD oscillator calibration */ - ebx = div_ll_X_l_rem(((u64) (s->config.f_if + df_tuner) << 28) + - (s->f_osc >> 1), s->f_osc, &dummy); + ebx = div64_64(((u64) (s->config.f_if + df_tuner) << 28) + + (s->f_osc >> 1), (u64)s->f_osc); } ebx &= 0xfffffff; if (fep->inversion == INVERSION_ON) -- cgit v1.2.3 From 22b0119e09d6e7d671535c61de27753a5e1a0a63 Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Wed, 30 Apr 2008 09:52:50 -0300 Subject: V4L/DVB (7812): 2.6.25-rc5-mm1 specifc div64_u64 fixes Rename a few more div64_u64 which are only in -mm. Signed-off-by: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/drx397xD.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c index af435466212..d71cce93d08 100644 --- a/drivers/media/dvb/frontends/drx397xD.c +++ b/drivers/media/dvb/frontends/drx397xD.c @@ -1026,13 +1026,13 @@ static int drx_tune(struct drx397xD_state *s, { /* Configure bandwidth specific factor */ - ebx = div64_64(((u64) (s->f_osc) << 21) + (ebx >> 1), + ebx = div64_u64(((u64) (s->f_osc) << 21) + (ebx >> 1), (u64)ebx) - 0x800000; EXIT_RC(WR16(s, 0x0c50010, ebx & 0xffff)); EXIT_RC(WR16(s, 0x0c50011, ebx >> 16)); /* drx397xD oscillator calibration */ - ebx = div64_64(((u64) (s->config.f_if + df_tuner) << 28) + + ebx = div64_u64(((u64) (s->config.f_if + df_tuner) << 28) + (s->f_osc >> 1), (u64)s->f_osc); } ebx &= 0xfffffff; -- cgit v1.2.3 From e272ae088fccf0e98ee0042392bd52a3455f28bd Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 8 Jul 2008 12:56:04 -0300 Subject: V4L/DVB (8247): Fix a const pointer assignment error in the drx397xD demodulator driver Fix an assignment of a const pointer to a non-const pointer in the drx397xD demodulator driver. This was introduced in patch eb9bd0e567365d4f607d32d8c41e201da65aa971. Signed-off-by: David Howells Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/drx397xD.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c index d71cce93d08..3cbed874a6f 100644 --- a/drivers/media/dvb/frontends/drx397xD.c +++ b/drivers/media/dvb/frontends/drx397xD.c @@ -73,7 +73,7 @@ static struct { const struct firmware *file; rwlock_t lock; int refcnt; - u8 *data[ARRAY_SIZE(blob_name)]; + const u8 *data[ARRAY_SIZE(blob_name)]; } fw[] = { #define _FW_ENTRY(a, b) { \ .name = a, \ @@ -109,7 +109,7 @@ static void drx_release_fw(struct drx397xD_state *s) static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix) { - u8 *data; + const u8 *data; size_t size, len; int i = 0, j, rc = -EINVAL; @@ -193,7 +193,7 @@ static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix) static int write_fw(struct drx397xD_state *s, blob_ix_t ix) { struct i2c_msg msg = {.addr = s->config.demod_address,.flags = 0 }; - u8 *data; + const u8 *data; int len, rc = 0, i = 0; if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) { @@ -214,7 +214,7 @@ static int write_fw(struct drx397xD_state *s, blob_ix_t ix) case 0: /* bytecode */ len = data[i++]; msg.len = len; - msg.buf = &data[i]; + msg.buf = (__u8 *) &data[i]; if (i2c_transfer(s->i2c, &msg, 1) != 1) { rc = -EIO; goto exit_rc; -- cgit v1.2.3 From 7fd4828f6cc5bd4339ff58e372ccb5f528548b30 Mon Sep 17 00:00:00 2001 From: Igor M Liplianin Date: Sun, 20 Jul 2008 08:05:50 -0300 Subject: V4L/DVB (8421): Adds support for Dvbworld DVB-S 2102 USB card Signed-off-by: Igor M Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 8 + drivers/media/dvb/dvb-usb/Makefile | 3 + drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + drivers/media/dvb/dvb-usb/dw2102.c | 425 ++++++++++++++++++++++++++++++++ drivers/media/dvb/dvb-usb/dw2102.h | 9 + drivers/media/dvb/frontends/z0194a.h | 97 ++++++++ 6 files changed, 543 insertions(+) create mode 100644 drivers/media/dvb/dvb-usb/dw2102.c create mode 100644 drivers/media/dvb/dvb-usb/dw2102.h create mode 100644 drivers/media/dvb/frontends/z0194a.h (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index a577c0f89f6..3c663c65ef6 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -246,6 +246,14 @@ config DVB_USB_AF9005_REMOTE Say Y here to support the default remote control decoding for the Afatech AF9005 based receiver. +config DVB_USB_DW2102 + tristate "DvbWorld 2102 DVB-S USB2.0 receiver" + depends on DVB_USB + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_PLL if !DVB_FE_CUSTOMISE + help + Say Y here to support the DvbWorld 2102 DVB-S USB2.0 receiver. + config DVB_USB_ANYSEE tristate "Anysee DVB-T/C USB2.0 support" depends on DVB_USB diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 44c11e45e56..e206f1ea002 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -64,6 +64,9 @@ obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o dvb-usb-anysee-objs = anysee.o obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o +dvb-usb-dw2102-objs = dw2102.o +obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o + EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ # due to tuner-xc3028 EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index e5238b31e94..029b437caf9 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -204,5 +204,6 @@ #define USB_PID_ASUS_U3000 0x171f #define USB_PID_ASUS_U3100 0x173f #define USB_PID_YUAN_EC372S 0x1edc +#define USB_PID_DW2102 0x2102 #endif diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c new file mode 100644 index 00000000000..a4d898b44e5 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -0,0 +1,425 @@ +/* DVB USB framework compliant Linux driver for the DVBWorld DVB-S 2102 Card +* +* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) +* +* 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, version 2. +* +* see Documentation/dvb/README.dvb-usb for more information +*/ +#include +#include "dw2102.h" +#include "stv0299.h" +#include "z0194a.h" + +#ifndef USB_PID_DW2102 +#define USB_PID_DW2102 0x2102 +#endif + +#define DW2102_READ_MSG 0 +#define DW2102_WRITE_MSG 1 + +#define REG_1F_SYMBOLRATE_BYTE0 0x1f +#define REG_20_SYMBOLRATE_BYTE1 0x20 +#define REG_21_SYMBOLRATE_BYTE2 0x21 + +#define DW2102_VOLTAGE_CTRL (0x1800) +#define DW2102_RC_QUERY (0x1a00) + +struct dw2102_state { + u32 last_key_pressed; +}; +struct dw2102_rc_keys { + u32 keycode; + u32 event; +}; + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int dw2102_op_rw(struct usb_device *dev, u8 request, u16 value, + u8 *data, u16 len, int flags) +{ + int ret; + u8 u8buf[len]; + + unsigned int pipe = (flags == DW2102_READ_MSG) ? + usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0); + u8 request_type = (flags == DW2102_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; + + if (flags == DW2102_WRITE_MSG) + memcpy(u8buf, data, len); + ret = usb_control_msg(dev, pipe, request, + request_type | USB_TYPE_VENDOR, value, 0 , u8buf, len, 2000); + + if (flags == DW2102_READ_MSG) + memcpy(data, u8buf, len); + return ret; +} + +/* I2C */ + +static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ +struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i = 0, ret = 0; + u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0}; + u8 request; + u16 value; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + switch (num) { + case 2: + /* read stv0299 register */ + request = 0xb5; + value = msg[0].buf[0];/* register */ + for (i = 0; i < msg[1].len; i++) { + value = value + i; + ret = dw2102_op_rw(d->udev, 0xb5, + value, buf6, 2, DW2102_READ_MSG); + msg[1].buf[i] = buf6[0]; + + } + break; + case 1: + switch (msg[0].addr) { + case 0x68: + /* write to stv0299 register */ + buf6[0] = 0x2a; + buf6[1] = msg[0].buf[0]; + buf6[2] = msg[0].buf[1]; + ret = dw2102_op_rw(d->udev, 0xb2, + 0, buf6, 3, DW2102_WRITE_MSG); + break; + case 0x60: + if (msg[0].flags == 0) { + /* write to tuner pll */ + buf6[0] = 0x2c; + buf6[1] = 5; + buf6[2] = 0xc0; + buf6[3] = msg[0].buf[0]; + buf6[4] = msg[0].buf[1]; + buf6[5] = msg[0].buf[2]; + buf6[6] = msg[0].buf[3]; + ret = dw2102_op_rw(d->udev, 0xb2, + 0, buf6, 7, DW2102_WRITE_MSG); + } else { + /* write to tuner pll */ + ret = dw2102_op_rw(d->udev, 0xb5, + 0, buf6, 1, DW2102_READ_MSG); + msg[0].buf[0] = buf6[0]; + } + break; + case (DW2102_RC_QUERY): + ret = dw2102_op_rw(d->udev, 0xb8, + 0, buf6, 2, DW2102_READ_MSG); + msg[0].buf[0] = buf6[0]; + msg[0].buf[1] = buf6[1]; + break; + case (DW2102_VOLTAGE_CTRL): + buf6[0] = 0x30; + buf6[1] = msg[0].buf[0]; + ret = dw2102_op_rw(d->udev, 0xb2, + 0, buf6, 2, DW2102_WRITE_MSG); + break; + } + + break; + } + + mutex_unlock(&d->i2c_mutex); + return num; +} + +static u32 dw2102_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm dw2102_i2c_algo = { + .master_xfer = dw2102_i2c_transfer, + .functionality = dw2102_i2c_func, +}; + +static int dw2102_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + static u8 command_13v[1] = {0x00}; + static u8 command_18v[1] = {0x01}; + struct i2c_msg msg[] = { + {.addr = DW2102_VOLTAGE_CTRL, .flags = 0, + .buf = command_13v, .len = 1}, + }; + + struct dvb_usb_adapter *udev_adap = + (struct dvb_usb_adapter *)(fe->dvb->priv); + if (voltage == SEC_VOLTAGE_18) + msg[0].buf = command_18v; + i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1); + return 0; +} + +static int dw2102_frontend_attach(struct dvb_usb_adapter *d) +{ + d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config, + &d->dev->i2c_adap); + if (d->fe != NULL) { + d->fe->ops.set_voltage = dw2102_set_voltage; + info("Attached stv0299!\n"); + return 0; + } + return -EIO; +} + +static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(dvb_pll_attach, adap->fe, 0x60, + &adap->dev->i2c_adap, DVB_PLL_OPERA1); + return 0; +} + +static struct dvb_usb_rc_key dw2102_rc_keys[] = { + { 0xf8, 0x0a, KEY_Q }, /*power*/ + { 0xf8, 0x0c, KEY_M }, /*mute*/ + { 0xf8, 0x11, KEY_1 }, + { 0xf8, 0x12, KEY_2 }, + { 0xf8, 0x13, KEY_3 }, + { 0xf8, 0x14, KEY_4 }, + { 0xf8, 0x15, KEY_5 }, + { 0xf8, 0x16, KEY_6 }, + { 0xf8, 0x17, KEY_7 }, + { 0xf8, 0x18, KEY_8 }, + { 0xf8, 0x19, KEY_9 }, + { 0xf8, 0x10, KEY_0 }, + { 0xf8, 0x1c, KEY_PAGEUP }, /*ch+*/ + { 0xf8, 0x0f, KEY_PAGEDOWN }, /*ch-*/ + { 0xf8, 0x1a, KEY_O }, /*vol+*/ + { 0xf8, 0x0e, KEY_Z }, /*vol-*/ + { 0xf8, 0x04, KEY_R }, /*rec*/ + { 0xf8, 0x09, KEY_D }, /*fav*/ + { 0xf8, 0x08, KEY_BACKSPACE }, /*rewind*/ + { 0xf8, 0x07, KEY_A }, /*fast*/ + { 0xf8, 0x0b, KEY_P }, /*pause*/ + { 0xf8, 0x02, KEY_ESC }, /*cancel*/ + { 0xf8, 0x03, KEY_G }, /*tab*/ + { 0xf8, 0x00, KEY_UP }, /*up*/ + { 0xf8, 0x1f, KEY_ENTER }, /*ok*/ + { 0xf8, 0x01, KEY_DOWN }, /*down*/ + { 0xf8, 0x05, KEY_C }, /*cap*/ + { 0xf8, 0x06, KEY_S }, /*stop*/ + { 0xf8, 0x40, KEY_F }, /*full*/ + { 0xf8, 0x1e, KEY_W }, /*tvmode*/ + { 0xf8, 0x1b, KEY_B }, /*recall*/ + +}; + + + +static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + struct dw2102_state *st = d->priv; + u8 key[2]; + struct i2c_msg msg[] = { + {.addr = DW2102_RC_QUERY, .flags = I2C_M_RD, .buf = key, + .len = 2}, + }; + int i; + + *state = REMOTE_NO_KEY_PRESSED; + if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) { + for (i = 0; i < ARRAY_SIZE(dw2102_rc_keys); i++) { + if (dw2102_rc_keys[i].data == msg[0].buf[0]) { + *state = REMOTE_KEY_PRESSED; + *event = dw2102_rc_keys[i].event; + st->last_key_pressed = + dw2102_rc_keys[i].event; + break; + } + st->last_key_pressed = 0; + } + } + /* info("key: %x %x\n",key[0],key[1]); */ + return 0; +} + +static struct usb_device_id dw2102_table[] = { + {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, + {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, + { } +}; + +MODULE_DEVICE_TABLE(usb, dw2102_table); + +static int dw2102_load_firmware(struct usb_device *dev, + const struct firmware *frmwr) +{ + u8 *b, *p; + int ret = 0, i; + u8 reset; + u8 reset16 [] = {0, 0, 0, 0, 0, 0, 0}; + const struct firmware *fw; + const char *filename = "dvb-usb-dw2101.fw"; + switch (dev->descriptor.idProduct) { + case 0x2101: + ret = request_firmware(&fw, filename, &dev->dev); + if (ret != 0) { + err("did not find the firmware file. (%s) " + "Please see linux/Documentation/dvb/ for more details " + "on firmware-problems.", filename); + return ret; + } + break; + case USB_PID_DW2102: + fw = frmwr; + break; + } + info("start downloading DW2102 firmware"); + p = kmalloc(fw->size, GFP_KERNEL); + reset = 1; + /*stop the CPU*/ + dw2102_op_rw(dev, 0xa0, 0x7f92, &reset, 1, DW2102_WRITE_MSG); + dw2102_op_rw(dev, 0xa0, 0xe600, &reset, 1, DW2102_WRITE_MSG); + + if (p != NULL) { + memcpy(p, fw->data, fw->size); + for (i = 0; i < fw->size; i += 0x40) { + b = (u8 *) p + i; + if (dw2102_op_rw + (dev, 0xa0, i, b , 0x40, + DW2102_WRITE_MSG) != 0x40 + ) { + err("error while transferring firmware"); + ret = -EINVAL; + break; + } + } + /* restart the CPU */ + reset = 0; + if (ret || dw2102_op_rw + (dev, 0xa0, 0x7f92, &reset, 1, + DW2102_WRITE_MSG) != 1) { + err("could not restart the USB controller CPU."); + ret = -EINVAL; + } + if (ret || dw2102_op_rw + (dev, 0xa0, 0xe600, &reset, 1, + DW2102_WRITE_MSG) != 1) { + err("could not restart the USB controller CPU."); + ret = -EINVAL; + } + /* init registers */ + switch (dev->descriptor.idProduct) { + case USB_PID_DW2102: + dw2102_op_rw + (dev, 0xbf, 0x0040, &reset, 0, + DW2102_WRITE_MSG); + dw2102_op_rw + (dev, 0xb9, 0x0000, &reset16[0], 2, + DW2102_READ_MSG); + break; + case 0x2101: + dw2102_op_rw + (dev, 0xbc, 0x0030, &reset16[0], 2, + DW2102_READ_MSG); + dw2102_op_rw + (dev, 0xba, 0x0000, &reset16[0], 7, + DW2102_READ_MSG); + dw2102_op_rw + (dev, 0xba, 0x0000, &reset16[0], 7, + DW2102_READ_MSG); + dw2102_op_rw + (dev, 0xb9, 0x0000, &reset16[0], 2, + DW2102_READ_MSG); + break; + } + kfree(p); + } + return ret; +} + +static struct dvb_usb_device_properties dw2102_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-dw2102.fw", + .size_of_priv = sizeof(struct dw2102_state), + .no_reconnect = 1, + + .i2c_algo = &dw2102_i2c_algo, + .rc_key_map = dw2102_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dw2102_rc_keys), + .rc_interval = 150, + .rc_query = dw2102_rc_query, + + .generic_bulk_ctrl_endpoint = 0x81, + /* parameter for the MPEG2-data transfer */ + .num_adapters = 1, + .download_firmware = dw2102_load_firmware, + .adapter = { + { + .frontend_attach = dw2102_frontend_attach, + .streaming_ctrl = NULL, + .tuner_attach = dw2102_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, + .num_device_descs = 2, + .devices = { + {"DVBWorld DVB-S 2102 USB2.0", + {&dw2102_table[0], NULL}, + {NULL}, + }, + {"DVBWorld DVB-S 2101 USB2.0", + {&dw2102_table[1], NULL}, + {NULL}, + }, + } +}; + +static int dw2102_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf, &dw2102_properties, + THIS_MODULE, NULL, adapter_nr); +} + +static struct usb_driver dw2102_driver = { + .name = "dw2102", + .probe = dw2102_probe, + .disconnect = dvb_usb_device_exit, + .id_table = dw2102_table, +}; + +static int __init dw2102_module_init(void) +{ + int ret = usb_register(&dw2102_driver); + if (ret) + err("usb_register failed. Error number %d", ret); + + return ret; +} + +static void __exit dw2102_module_exit(void) +{ + usb_deregister(&dw2102_driver); +} + +module_init(dw2102_module_init); +module_exit(dw2102_module_exit); + +MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); +MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101 2102 USB2.0 device"); +MODULE_VERSION("0.1"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dw2102.h b/drivers/media/dvb/dvb-usb/dw2102.h new file mode 100644 index 00000000000..cb5873752e4 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dw2102.h @@ -0,0 +1,9 @@ +#ifndef _DW2102_H_ +#define _DW2102_H_ + +#define DVB_USB_LOG_PREFIX "dw2102" +#include + +extern int dvb_usb_dw2102_debug; +#define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args) +#endif diff --git a/drivers/media/dvb/frontends/z0194a.h b/drivers/media/dvb/frontends/z0194a.h new file mode 100644 index 00000000000..b5ca9e75421 --- /dev/null +++ b/drivers/media/dvb/frontends/z0194a.h @@ -0,0 +1,97 @@ +/* z0194a.h Sharp z0194a tuner support +* +* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) +* +* 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, version 2. +* +* see Documentation/dvb/README.dvb-usb for more information +*/ + +#ifndef Z0194A +#define Z0194A + +static int sharp_z0194a__set_symbol_rate(struct dvb_frontend *fe, + u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { + aclk = 0xb7; bclk = 0x47; } + else if (srate < 3000000) { + aclk = 0xb7; bclk = 0x4b; } + else if (srate < 7000000) { + aclk = 0xb7; bclk = 0x4f; } + else if (srate < 14000000) { + aclk = 0xb7; bclk = 0x53; } + else if (srate < 30000000) { + aclk = 0xb6; bclk = 0x53; } + else if (srate < 45000000) { + aclk = 0xb4; bclk = 0x51; } + + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, (ratio) & 0xf0); + + return 0; +} + +static u8 sharp_z0194a__inittab[] = { + 0x01, 0x15, + 0x02, 0x00, + 0x03, 0x00, + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ + 0x06, 0x40, /* DAC not used, set to high impendance mode */ + 0x07, 0x00, /* DAC LSB */ + 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ + 0x09, 0x00, /* FIFO */ + 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ + 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ + 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ + 0x10, 0x3f, /* AGC2 0x3d */ + 0x11, 0x84, + 0x12, 0xb9, + 0x15, 0xc9, /* lock detector threshold */ + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, /* out imp: normal out type: parallel FEC mode:0 */ + 0x29, 0x1e, /* 1/2 threshold */ + 0x2a, 0x14, /* 2/3 threshold */ + 0x2b, 0x0f, /* 3/4 threshold */ + 0x2c, 0x09, /* 5/6 threshold */ + 0x2d, 0x05, /* 7/8 threshold */ + 0x2e, 0x01, + 0x31, 0x1f, /* test all FECs */ + 0x32, 0x19, /* viterbi and synchro search */ + 0x33, 0xfc, /* rs control */ + 0x34, 0x93, /* error control */ + 0x0f, 0x52, + 0xff, 0xff +}; + +static struct stv0299_config sharp_z0194a_config = { + .demod_address = 0x68, + .inittab = sharp_z0194a__inittab, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .lock_output = STV0229_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = sharp_z0194a__set_symbol_rate, +}; + +#endif -- cgit v1.2.3 From bcf4562ecbc35dabacc562fdf6c92218ca59ca94 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 18 Jul 2008 20:14:31 -0300 Subject: V4L/DVB (8422): cs5345: fix incorrect mask with VIDIOC_DBG_S_REGISTER Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cs5345.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c index 1c3fa3a7470..61d14d26686 100644 --- a/drivers/media/video/cs5345.c +++ b/drivers/media/video/cs5345.c @@ -111,7 +111,7 @@ static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg) if (cmd == VIDIOC_DBG_G_REGISTER) reg->val = cs5345_read(client, reg->reg & 0x1f); else - cs5345_write(client, reg->reg & 0x1f, reg->val & 0x1f); + cs5345_write(client, reg->reg & 0x1f, reg->val & 0xff); break; } #endif -- cgit v1.2.3 From 82fc52a886aaff8a1605f9d16240e74ddac8570c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 19 Jul 2008 08:34:12 -0300 Subject: V4L/DVB (8423): cx18: remove firmware size check This check was an ivtv leftover that served no purpose for the cx18. Removed it, as this allows the user to load different firmware versions. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-firmware.c | 54 ++++++++------------------------ 1 file changed, 13 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c index 2d630d9f749..78fadd2ada5 100644 --- a/drivers/media/video/cx18/cx18-firmware.c +++ b/drivers/media/video/cx18/cx18-firmware.c @@ -86,10 +86,6 @@ #define CX18_DSP0_INTERRUPT_MASK 0xd0004C -/* Encoder/decoder firmware sizes */ -#define CX18_FW_CPU_SIZE (158332) -#define CX18_FW_APU_SIZE (141200) - #define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */ #define APU_ROM_SYNC2 0x72646548 /* "rdeH" */ @@ -100,35 +96,22 @@ struct cx18_apu_rom_seghdr { u32 size; }; -static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx, long size) +static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx) { const struct firmware *fw = NULL; - int retries = 3; int i, j; + unsigned size; u32 __iomem *dst = (u32 __iomem *)mem; const u32 *src; -retry: - if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) { - CX18_ERR("Unable to open firmware %s (must be %ld bytes)\n", - fn, size); + if (request_firmware(&fw, fn, &cx->dev->dev)) { + CX18_ERR("Unable to open firmware %s\n", fn); CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n"); return -ENOMEM; } src = (const u32 *)fw->data; - if (fw->size != size) { - /* Due to race conditions in firmware loading (esp. with - udev <0.95) the wrong file was sometimes loaded. So we check - filesizes to see if at least the right-sized file was - loaded. If not, then we retry. */ - CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", - fn, size, fw->size); - release_firmware(fw); - retries--; - goto retry; - } for (i = 0; i < fw->size; i += 4096) { setup_page(i); for (j = i; j < fw->size && j < i + 4096; j += 4) { @@ -145,15 +128,16 @@ retry: } if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); + size = fw->size; release_firmware(fw); return size; } -static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, long size) +static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx) { const struct firmware *fw = NULL; - int retries = 3; int i, j; + unsigned size; const u32 *src; struct cx18_apu_rom_seghdr seghdr; const u8 *vers; @@ -161,10 +145,8 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, u32 apu_version = 0; int sz; -retry: - if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) { - CX18_ERR("unable to open firmware %s (must be %ld bytes)\n", - fn, size); + if (request_firmware(&fw, fn, &cx->dev->dev)) { + CX18_ERR("unable to open firmware %s\n", fn); CX18_ERR("did you put the firmware in the hotplug firmware directory?\n"); return -ENOMEM; } @@ -173,19 +155,8 @@ retry: vers = fw->data + sizeof(seghdr); sz = fw->size; - if (fw->size != size) { - /* Due to race conditions in firmware loading (esp. with - udev <0.95) the wrong file was sometimes loaded. So we check - filesizes to see if at least the right-sized file was - loaded. If not, then we retry. */ - CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", - fn, size, fw->size); - release_firmware(fw); - retries--; - goto retry; - } apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32]; - while (offset + sizeof(seghdr) < size) { + while (offset + sizeof(seghdr) < fw->size) { /* TODO: byteswapping */ memcpy(&seghdr, src + offset / 4, sizeof(seghdr)); offset += sizeof(seghdr); @@ -215,6 +186,7 @@ retry: if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n", fn, apu_version, fw->size); + size = fw->size; release_firmware(fw); /* Clear bit0 for APU to start from 0 */ write_reg(read_reg(0xc72030) & ~1, 0xc72030); @@ -340,7 +312,7 @@ int cx18_firmware_init(struct cx18 *cx) /* Only if the processor is not running */ if (read_reg(CX18_PROC_SOFT_RESET) & 8) { int sz = load_apu_fw_direct("v4l-cx23418-apu.fw", - cx->enc_mem, cx, CX18_FW_APU_SIZE); + cx->enc_mem, cx); write_enc(0xE51FF004, 0); write_enc(0xa00000, 4); /* todo: not hardcoded */ @@ -348,7 +320,7 @@ int cx18_firmware_init(struct cx18 *cx) cx18_msleep_timeout(500, 0); sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw", - cx->enc_mem, cx, CX18_FW_CPU_SIZE); + cx->enc_mem, cx); if (sz > 0) { int retries = 0; -- cgit v1.2.3 From c60f2b5c1defb6b1345968e1c65c2008c221d57d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 17 Jul 2008 17:30:47 -0300 Subject: V4L/DVB (8425): v4l: fix checkpatch errors introduced by recent commits Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_ceu_camera.c | 1 + drivers/media/video/videobuf-dma-contig.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 012005e1a77..f7ca3cb9340 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -91,6 +91,7 @@ struct sh_mobile_ceu_dev { void __iomem *base; unsigned long video_limit; + /* lock used to protect videobuf */ spinlock_t lock; struct list_head capture; struct videobuf_buffer *active; diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c index 03f20acb668..31944b11e6e 100644 --- a/drivers/media/video/videobuf-dma-contig.c +++ b/drivers/media/video/videobuf-dma-contig.c @@ -28,10 +28,10 @@ struct videobuf_dma_contig_memory { }; #define MAGIC_DC_MEM 0x0733ac61 -#define MAGIC_CHECK(is, should) \ - if (unlikely((is) != (should))) { \ - pr_err("magic mismatch: %x expected %x\n", is, should); \ - BUG(); \ +#define MAGIC_CHECK(is, should) \ + if (unlikely((is) != (should))) { \ + pr_err("magic mismatch: %x expected %x\n", (is), (should)); \ + BUG(); \ } static void -- cgit v1.2.3 From 6aabcdffd1a5f8f5b906696e58069c4f8fced542 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Thu, 3 Jul 2008 10:45:38 -0400 Subject: Input: serio - offload resume to kseriod When resuming AUX ports psmouse driver calls psmouse_extensions() to determine if the attached mouse is still the same, which may take a while to complete for generic mice. Offload the resume process to kseriod so the rest of the system may continue resuming without waiting for the mouse. Signed-off-by: Shaohua Li Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 55 ++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 78f2abb5c11..2f12d60eee3 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -63,8 +63,9 @@ static LIST_HEAD(serio_list); static struct bus_type serio_bus; static void serio_add_port(struct serio *serio); -static void serio_reconnect_port(struct serio *serio); +static int serio_reconnect_port(struct serio *serio); static void serio_disconnect_port(struct serio *serio); +static void serio_reconnect_chain(struct serio *serio); static void serio_attach_driver(struct serio_driver *drv); static int serio_connect_driver(struct serio *serio, struct serio_driver *drv) @@ -161,6 +162,7 @@ static void serio_find_driver(struct serio *serio) enum serio_event_type { SERIO_RESCAN_PORT, SERIO_RECONNECT_PORT, + SERIO_RECONNECT_CHAIN, SERIO_REGISTER_PORT, SERIO_ATTACH_DRIVER, }; @@ -315,6 +317,10 @@ static void serio_handle_event(void) serio_find_driver(event->object); break; + case SERIO_RECONNECT_CHAIN: + serio_reconnect_chain(event->object); + break; + case SERIO_ATTACH_DRIVER: serio_attach_driver(event->object); break; @@ -470,7 +476,7 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute * if (!strncmp(buf, "none", count)) { serio_disconnect_port(serio); } else if (!strncmp(buf, "reconnect", count)) { - serio_reconnect_port(serio); + serio_reconnect_chain(serio); } else if (!strncmp(buf, "rescan", count)) { serio_disconnect_port(serio); serio_find_driver(serio); @@ -619,15 +625,31 @@ static void serio_destroy_port(struct serio *serio) put_device(&serio->dev); } +/* + * Reconnect serio port (re-initialize attached device). + * If reconnect fails (old device is no longer attached or + * there was no device to begin with) we do full rescan in + * hope of finding a driver for the port. + */ +static int serio_reconnect_port(struct serio *serio) +{ + int error = serio_reconnect_driver(serio); + + if (error) { + serio_disconnect_port(serio); + serio_find_driver(serio); + } + + return error; +} + /* * Reconnect serio port and all its children (re-initialize attached devices) */ -static void serio_reconnect_port(struct serio *serio) +static void serio_reconnect_chain(struct serio *serio) { do { - if (serio_reconnect_driver(serio)) { - serio_disconnect_port(serio); - serio_find_driver(serio); + if (serio_reconnect_port(serio)) { /* Ok, old children are now gone, we are done */ break; } @@ -673,7 +695,7 @@ void serio_rescan(struct serio *serio) void serio_reconnect(struct serio *serio) { - serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT); + serio_queue_event(serio, NULL, SERIO_RECONNECT_CHAIN); } /* @@ -927,19 +949,16 @@ static int serio_suspend(struct device *dev, pm_message_t state) static int serio_resume(struct device *dev) { - struct serio *serio = to_serio_port(dev); - - if (dev->power.power_state.event != PM_EVENT_ON && - serio_reconnect_driver(serio)) { - /* - * Driver re-probing can take a while, so better let kseriod - * deal with it. - */ - serio_rescan(serio); + /* + * Driver reconnect can take a while, so better let kseriod + * deal with it. + */ + if (dev->power.power_state.event != PM_EVENT_ON) { + dev->power.power_state = PMSG_ON; + serio_queue_event(to_serio_port(dev), NULL, + SERIO_RECONNECT_PORT); } - dev->power.power_state = PMSG_ON; - return 0; } #endif /* CONFIG_PM */ -- cgit v1.2.3 From 53703659ab559a58a3058e69aeb59c06d4872358 Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Wed, 23 Jul 2008 13:57:50 -0400 Subject: Input: uinput - remove duplicate include Remove duplicate include file in drivers/input/misc/uinput.c. Signed-off-by: Huang Weiyi Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 2bcfa0b3506..223d56d5555 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -37,7 +37,6 @@ #include #include #include -#include static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { -- cgit v1.2.3 From 494f685775ee4c2f3db4081209f00ff0633243fc Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Wed, 23 Jul 2008 14:16:19 -0400 Subject: Input: ads7846 - fix sparse endian warnings Also remove the temporary pointer and use ->rx_buf directly. Signed-off-by: Harvey Harrison Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 907a45fe9d4..4d060321514 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -633,19 +633,17 @@ static void ads7846_rx_val(void *ads) struct ads7846 *ts = ads; struct spi_message *m; struct spi_transfer *t; - u16 *rx_val; int val; int action; int status; m = &ts->msg[ts->msg_idx]; t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); - rx_val = t->rx_buf; /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding; * built from two 8 bit values written msb-first. */ - val = be16_to_cpu(*rx_val) >> 3; + val = be16_to_cpup((__be16 *)t->rx_buf) >> 3; action = ts->filter(ts->filter_data, ts->msg_idx, &val); switch (action) { @@ -659,7 +657,7 @@ static void ads7846_rx_val(void *ads) m = ts->last_msg; break; case ADS7846_FILTER_OK: - *rx_val = val; + *(u16 *)t->rx_buf = val; ts->tc.ignore = 0; m = &ts->msg[++ts->msg_idx]; break; -- cgit v1.2.3 From 9460b6529d8a0bfabf241ddda8b0e469d219844c Mon Sep 17 00:00:00 2001 From: Hans-Christian Egtvedt Date: Wed, 23 Jul 2008 14:38:27 -0400 Subject: Input: ads7846 - optimize order of calculating Rt in ads7846_rx() Alter the if expression for calculating Rt. The old implementation would run unnecessary code when the ADS7843 device was used. The patch also fixes the code style to kernel standard. Signed-off-by: Hans-Christian Egtvedt Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 4d060321514..ce6f48c695f 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -517,7 +517,9 @@ static void ads7846_rx(void *ads) if (x == MAX_12BIT) x = 0; - if (likely(x && z1)) { + if (ts->model == 7843) { + Rt = ts->pressure_max / 2; + } else if (likely(x && z1)) { /* compute touch pressure resistance using equation #2 */ Rt = z2; Rt -= z1; @@ -525,11 +527,9 @@ static void ads7846_rx(void *ads) Rt *= ts->x_plate_ohms; Rt /= z1; Rt = (Rt + 2047) >> 12; - } else + } else { Rt = 0; - - if (ts->model == 7843) - Rt = ts->pressure_max / 2; + } /* Sample found inconsistent by debouncing or pressure is beyond * the maximum. Don't report it to user space, repeat at least -- cgit v1.2.3 From c9f21aaff1d1fb5629325130af469532d19beb93 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 23 Jul 2008 12:05:51 -0700 Subject: md: move async_tx_issue_pending_all outside spin_lock_irq Some dma drivers need to call spin_lock_bh in their device_issue_pending routines. This change avoids: WARNING: at kernel/softirq.c:136 local_bh_enable_ip+0x3a/0x85() Signed-off-by: Dan Williams --- drivers/md/raid5.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 42a480ba767..8a6f101d322 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3809,10 +3809,8 @@ static void raid5d(mddev_t *mddev) sh = __get_priority_stripe(conf); - if (!sh) { - async_tx_issue_pending_all(); + if (!sh) break; - } spin_unlock_irq(&conf->device_lock); handled++; @@ -3825,6 +3823,7 @@ static void raid5d(mddev_t *mddev) spin_unlock_irq(&conf->device_lock); + async_tx_issue_pending_all(); unplug_slaves(mddev); pr_debug("--- raid5d inactive\n"); -- cgit v1.2.3 From 27a5e6d3fcce73ceeee8f3bdc9a30c4564233800 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 20 Jul 2008 08:43:17 -0300 Subject: V4L/DVB (8427): videodev: split off the ioctl handling into v4l2-ioctl.c videodev.c became top-heavy so all the ioctl processing has been split off into v4l2-ioctl.c. This means videodev.c is back to its original purpose: creating and registering v4l devices. Since videodev.c and v4l2-ioctl.c should still remain one module (as least for now) I also had to rename videodev.c to v4l2-dev.c to prevent a circular dependency when building a videodev.ko module. This is not a bad thing, since the source and header now have the same name. And the v4l2- prefix is useful to see which sources are generic v4l2 support code. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 2 + drivers/media/video/v4l2-dev.c | 424 ++++++++ drivers/media/video/videodev.c | 2262 ---------------------------------------- 3 files changed, 426 insertions(+), 2262 deletions(-) create mode 100644 drivers/media/video/v4l2-dev.c (limited to 'drivers') diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 45d5db5abb1..9de1e488524 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -10,6 +10,8 @@ msp3400-objs := msp3400-driver.o msp3400-kthreads.o stkwebcam-objs := stk-webcam.o stk-sensor.o +videodev-objs := v4l2-dev.o v4l2-ioctl.o + obj-$(CONFIG_VIDEO_DEV) += videodev.o compat_ioctl32.o v4l2-int-device.o obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c new file mode 100644 index 00000000000..2dd82b16bc3 --- /dev/null +++ b/drivers/media/video/v4l2-dev.c @@ -0,0 +1,424 @@ +/* + * Video capture interface for Linux version 2 + * + * A generic video device interface for the LINUX operating system + * using a set of device structures/vectors for low level operations. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Alan Cox, (version 1) + * Mauro Carvalho Chehab (version 2) + * + * Fixes: 20000516 Claudio Matsuoka + * - Added procfs support + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define VIDEO_NUM_DEVICES 256 +#define VIDEO_NAME "video4linux" + +/* + * sysfs stuff + */ + +static ssize_t show_index(struct device *cd, + struct device_attribute *attr, char *buf) +{ + struct video_device *vfd = container_of(cd, struct video_device, + class_dev); + return sprintf(buf, "%i\n", vfd->index); +} + +static ssize_t show_name(struct device *cd, + struct device_attribute *attr, char *buf) +{ + struct video_device *vfd = container_of(cd, struct video_device, + class_dev); + return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name); +} + +static struct device_attribute video_device_attrs[] = { + __ATTR(name, S_IRUGO, show_name, NULL), + __ATTR(index, S_IRUGO, show_index, NULL), + __ATTR_NULL +}; + +struct video_device *video_device_alloc(void) +{ + struct video_device *vfd; + + vfd = kzalloc(sizeof(*vfd), GFP_KERNEL); + return vfd; +} +EXPORT_SYMBOL(video_device_alloc); + +void video_device_release(struct video_device *vfd) +{ + kfree(vfd); +} +EXPORT_SYMBOL(video_device_release); + +static void video_release(struct device *cd) +{ + struct video_device *vfd = container_of(cd, struct video_device, + class_dev); + +#if 1 + /* needed until all drivers are fixed */ + if (!vfd->release) + return; +#endif + vfd->release(vfd); +} + +static struct class video_class = { + .name = VIDEO_NAME, + .dev_attrs = video_device_attrs, + .dev_release = video_release, +}; + +/* + * Active devices + */ + +static struct video_device *video_device[VIDEO_NUM_DEVICES]; +static DEFINE_MUTEX(videodev_lock); + +struct video_device *video_devdata(struct file *file) +{ + return video_device[iminor(file->f_path.dentry->d_inode)]; +} +EXPORT_SYMBOL(video_devdata); + +/* + * Open a video device - FIXME: Obsoleted + */ +static int video_open(struct inode *inode, struct file *file) +{ + unsigned int minor = iminor(inode); + int err = 0; + struct video_device *vfl; + const struct file_operations *old_fops; + + if (minor >= VIDEO_NUM_DEVICES) + return -ENODEV; + lock_kernel(); + mutex_lock(&videodev_lock); + vfl = video_device[minor]; + if (vfl == NULL) { + mutex_unlock(&videodev_lock); + request_module("char-major-%d-%d", VIDEO_MAJOR, minor); + mutex_lock(&videodev_lock); + vfl = video_device[minor]; + if (vfl == NULL) { + mutex_unlock(&videodev_lock); + unlock_kernel(); + return -ENODEV; + } + } + old_fops = file->f_op; + file->f_op = fops_get(vfl->fops); + if (file->f_op->open) + err = file->f_op->open(inode, file); + if (err) { + fops_put(file->f_op); + file->f_op = fops_get(old_fops); + } + fops_put(old_fops); + mutex_unlock(&videodev_lock); + unlock_kernel(); + return err; +} + +/* + * open/release helper functions -- handle exclusive opens + * Should be removed soon + */ +int video_exclusive_open(struct inode *inode, struct file *file) +{ + struct video_device *vfl = video_devdata(file); + int retval = 0; + + mutex_lock(&vfl->lock); + if (vfl->users) + retval = -EBUSY; + else + vfl->users++; + mutex_unlock(&vfl->lock); + return retval; +} +EXPORT_SYMBOL(video_exclusive_open); + +int video_exclusive_release(struct inode *inode, struct file *file) +{ + struct video_device *vfl = video_devdata(file); + + vfl->users--; + return 0; +} +EXPORT_SYMBOL(video_exclusive_release); + +/** + * get_index - assign stream number based on parent device + * @vdev: video_device to assign index number to, vdev->dev should be assigned + * @num: -1 if auto assign, requested number otherwise + * + * + * returns -ENFILE if num is already in use, a free index number if + * successful. + */ +static int get_index(struct video_device *vdev, int num) +{ + u32 used = 0; + const int max_index = sizeof(used) * 8 - 1; + int i; + + /* Currently a single v4l driver instance cannot create more than + 32 devices. + Increase to u64 or an array of u32 if more are needed. */ + if (num > max_index) { + printk(KERN_ERR "videodev: %s num is too large\n", __func__); + return -EINVAL; + } + + for (i = 0; i < VIDEO_NUM_DEVICES; i++) { + if (video_device[i] != NULL && + video_device[i] != vdev && + video_device[i]->dev == vdev->dev) { + used |= 1 << video_device[i]->index; + } + } + + if (num >= 0) { + if (used & (1 << num)) + return -ENFILE; + return num; + } + + i = ffz(used); + return i > max_index ? -ENFILE : i; +} + +static const struct file_operations video_fops; + +int video_register_device(struct video_device *vfd, int type, int nr) +{ + return video_register_device_index(vfd, type, nr, -1); +} +EXPORT_SYMBOL(video_register_device); + +/** + * video_register_device - register video4linux devices + * @vfd: video device structure we want to register + * @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 + * driver initialize function is called (if non %NULL). + * + * Zero is returned on success. + * + * Valid types are + * + * %VFL_TYPE_GRABBER - A frame grabber + * + * %VFL_TYPE_VTX - A teletext device + * + * %VFL_TYPE_VBI - Vertical blank data (undecoded) + * + * %VFL_TYPE_RADIO - A radio card + */ + +int video_register_device_index(struct video_device *vfd, int type, int nr, + int index) +{ + int i = 0; + int base; + int end; + int ret; + char *name_base; + + switch (type) { + case VFL_TYPE_GRABBER: + base = MINOR_VFL_TYPE_GRABBER_MIN; + end = MINOR_VFL_TYPE_GRABBER_MAX+1; + name_base = "video"; + break; + case VFL_TYPE_VTX: + base = MINOR_VFL_TYPE_VTX_MIN; + end = MINOR_VFL_TYPE_VTX_MAX+1; + name_base = "vtx"; + break; + case VFL_TYPE_VBI: + base = MINOR_VFL_TYPE_VBI_MIN; + end = MINOR_VFL_TYPE_VBI_MAX+1; + name_base = "vbi"; + break; + case VFL_TYPE_RADIO: + base = MINOR_VFL_TYPE_RADIO_MIN; + end = MINOR_VFL_TYPE_RADIO_MAX+1; + name_base = "radio"; + break; + default: + printk(KERN_ERR "%s called with unknown type: %d\n", + __func__, type); + return -1; + } + + /* pick a minor number */ + mutex_lock(&videodev_lock); + if (nr >= 0 && nr < end-base) { + /* use the one the driver asked for */ + i = base + nr; + if (NULL != video_device[i]) { + mutex_unlock(&videodev_lock); + return -ENFILE; + } + } else { + /* use first free */ + for (i = base; i < end; i++) + if (NULL == video_device[i]) + break; + if (i == end) { + mutex_unlock(&videodev_lock); + return -ENFILE; + } + } + video_device[i] = vfd; + vfd->minor = i; + + ret = get_index(vfd, index); + vfd->index = ret; + + mutex_unlock(&videodev_lock); + + if (ret < 0) { + printk(KERN_ERR "%s: get_index failed\n", __func__); + goto fail_minor; + } + + mutex_init(&vfd->lock); + + /* sysfs class */ + memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev)); + vfd->class_dev.class = &video_class; + vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); + if (vfd->dev) + vfd->class_dev.parent = vfd->dev; + sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base); + ret = device_register(&vfd->class_dev); + if (ret < 0) { + printk(KERN_ERR "%s: device_register failed\n", __func__); + goto fail_minor; + } + +#if 1 + /* needed until all drivers are fixed */ + if (!vfd->release) + printk(KERN_WARNING "videodev: \"%s\" has no release callback. " + "Please fix your driver for proper sysfs support, see " + "http://lwn.net/Articles/36850/\n", vfd->name); +#endif + return 0; + +fail_minor: + mutex_lock(&videodev_lock); + video_device[vfd->minor] = NULL; + vfd->minor = -1; + mutex_unlock(&videodev_lock); + return ret; +} +EXPORT_SYMBOL(video_register_device_index); + +/** + * video_unregister_device - unregister a video4linux device + * @vfd: the device to unregister + * + * 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) +{ + mutex_lock(&videodev_lock); + if (video_device[vfd->minor] != vfd) + panic("videodev: bad unregister"); + + video_device[vfd->minor] = NULL; + device_unregister(&vfd->class_dev); + mutex_unlock(&videodev_lock); +} +EXPORT_SYMBOL(video_unregister_device); + +/* + * Video fs operations + */ +static const struct file_operations video_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .open = video_open, +}; + +/* + * Initialise video for linux + */ + +static int __init videodev_init(void) +{ + int ret; + + printk(KERN_INFO "Linux video capture interface: v2.00\n"); + if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) { + printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR); + return -EIO; + } + + ret = class_register(&video_class); + if (ret < 0) { + unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME); + printk(KERN_WARNING "video_dev: class_register failed\n"); + return -EIO; + } + + return 0; +} + +static void __exit videodev_exit(void) +{ + class_unregister(&video_class); + unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME); +} + +module_init(videodev_init) +module_exit(videodev_exit) + +MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab "); +MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2"); +MODULE_LICENSE("GPL"); + + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 6616e657055..e69de29bb2d 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -1,2262 +0,0 @@ -/* - * Video capture interface for Linux version 2 - * - * A generic video device interface for the LINUX operating system - * using a set of device structures/vectors for low level operations. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alan Cox, (version 1) - * Mauro Carvalho Chehab (version 2) - * - * Fixes: 20000516 Claudio Matsuoka - * - Added procfs support - */ - -#define dbgarg(cmd, fmt, arg...) \ - do { \ - if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \ - printk(KERN_DEBUG "%s: ", vfd->name); \ - v4l_printk_ioctl(cmd); \ - printk(" " fmt, ## arg); \ - } \ - } while (0) - -#define dbgarg2(fmt, arg...) \ - do { \ - if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ - printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);\ - } while (0) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define __OLD_VIDIOC_ /* To allow fixing old calls*/ -#include - -#ifdef CONFIG_VIDEO_V4L1 -#include -#endif -#include -#include - -#define VIDEO_NUM_DEVICES 256 -#define VIDEO_NAME "video4linux" - -struct std_descr { - v4l2_std_id std; - const char *descr; -}; - -static const struct std_descr standards[] = { - { V4L2_STD_NTSC, "NTSC" }, - { V4L2_STD_NTSC_M, "NTSC-M" }, - { V4L2_STD_NTSC_M_JP, "NTSC-M-JP" }, - { V4L2_STD_NTSC_M_KR, "NTSC-M-KR" }, - { V4L2_STD_NTSC_443, "NTSC-443" }, - { V4L2_STD_PAL, "PAL" }, - { V4L2_STD_PAL_BG, "PAL-BG" }, - { V4L2_STD_PAL_B, "PAL-B" }, - { V4L2_STD_PAL_B1, "PAL-B1" }, - { V4L2_STD_PAL_G, "PAL-G" }, - { V4L2_STD_PAL_H, "PAL-H" }, - { V4L2_STD_PAL_I, "PAL-I" }, - { V4L2_STD_PAL_DK, "PAL-DK" }, - { V4L2_STD_PAL_D, "PAL-D" }, - { V4L2_STD_PAL_D1, "PAL-D1" }, - { V4L2_STD_PAL_K, "PAL-K" }, - { V4L2_STD_PAL_M, "PAL-M" }, - { V4L2_STD_PAL_N, "PAL-N" }, - { V4L2_STD_PAL_Nc, "PAL-Nc" }, - { V4L2_STD_PAL_60, "PAL-60" }, - { V4L2_STD_SECAM, "SECAM" }, - { V4L2_STD_SECAM_B, "SECAM-B" }, - { V4L2_STD_SECAM_G, "SECAM-G" }, - { V4L2_STD_SECAM_H, "SECAM-H" }, - { V4L2_STD_SECAM_DK, "SECAM-DK" }, - { V4L2_STD_SECAM_D, "SECAM-D" }, - { V4L2_STD_SECAM_K, "SECAM-K" }, - { V4L2_STD_SECAM_K1, "SECAM-K1" }, - { V4L2_STD_SECAM_L, "SECAM-L" }, - { V4L2_STD_SECAM_LC, "SECAM-Lc" }, - { 0, "Unknown" } -}; - -/* video4linux standard ID conversion to standard name - */ -const char *v4l2_norm_to_name(v4l2_std_id id) -{ - u32 myid = id; - int i; - - /* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle - 64 bit comparations. So, on that architecture, with some gcc - variants, compilation fails. Currently, the max value is 30bit wide. - */ - BUG_ON(myid != id); - - for (i = 0; standards[i].std; i++) - if (myid == standards[i].std) - break; - return standards[i].descr; -} -EXPORT_SYMBOL(v4l2_norm_to_name); - -/* Fill in the fields of a v4l2_standard structure according to the - 'id' and 'transmission' parameters. Returns negative on error. */ -int v4l2_video_std_construct(struct v4l2_standard *vs, - int id, const char *name) -{ - u32 index = vs->index; - - memset(vs, 0, sizeof(struct v4l2_standard)); - vs->index = index; - vs->id = id; - if (id & V4L2_STD_525_60) { - vs->frameperiod.numerator = 1001; - vs->frameperiod.denominator = 30000; - vs->framelines = 525; - } else { - vs->frameperiod.numerator = 1; - vs->frameperiod.denominator = 25; - vs->framelines = 625; - } - strlcpy(vs->name, name, sizeof(vs->name)); - return 0; -} -EXPORT_SYMBOL(v4l2_video_std_construct); - -/* ----------------------------------------------------------------- */ -/* some arrays for pretty-printing debug messages of enum types */ - -const char *v4l2_field_names[] = { - [V4L2_FIELD_ANY] = "any", - [V4L2_FIELD_NONE] = "none", - [V4L2_FIELD_TOP] = "top", - [V4L2_FIELD_BOTTOM] = "bottom", - [V4L2_FIELD_INTERLACED] = "interlaced", - [V4L2_FIELD_SEQ_TB] = "seq-tb", - [V4L2_FIELD_SEQ_BT] = "seq-bt", - [V4L2_FIELD_ALTERNATE] = "alternate", - [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb", - [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt", -}; -EXPORT_SYMBOL(v4l2_field_names); - -const char *v4l2_type_names[] = { - [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "vid-cap", - [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "vid-overlay", - [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "vid-out", - [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", - [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", - [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", - [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", - [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay", -}; -EXPORT_SYMBOL(v4l2_type_names); - -static const char *v4l2_memory_names[] = { - [V4L2_MEMORY_MMAP] = "mmap", - [V4L2_MEMORY_USERPTR] = "userptr", - [V4L2_MEMORY_OVERLAY] = "overlay", -}; - -#define prt_names(a, arr) ((((a) >= 0) && ((a) < ARRAY_SIZE(arr))) ? \ - arr[a] : "unknown") - -/* ------------------------------------------------------------------ */ -/* debug help functions */ - -#ifdef CONFIG_VIDEO_V4L1_COMPAT -static const char *v4l1_ioctls[] = { - [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP", - [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN", - [_IOC_NR(VIDIOCSCHAN)] = "VIDIOCSCHAN", - [_IOC_NR(VIDIOCGTUNER)] = "VIDIOCGTUNER", - [_IOC_NR(VIDIOCSTUNER)] = "VIDIOCSTUNER", - [_IOC_NR(VIDIOCGPICT)] = "VIDIOCGPICT", - [_IOC_NR(VIDIOCSPICT)] = "VIDIOCSPICT", - [_IOC_NR(VIDIOCCAPTURE)] = "VIDIOCCAPTURE", - [_IOC_NR(VIDIOCGWIN)] = "VIDIOCGWIN", - [_IOC_NR(VIDIOCSWIN)] = "VIDIOCSWIN", - [_IOC_NR(VIDIOCGFBUF)] = "VIDIOCGFBUF", - [_IOC_NR(VIDIOCSFBUF)] = "VIDIOCSFBUF", - [_IOC_NR(VIDIOCKEY)] = "VIDIOCKEY", - [_IOC_NR(VIDIOCGFREQ)] = "VIDIOCGFREQ", - [_IOC_NR(VIDIOCSFREQ)] = "VIDIOCSFREQ", - [_IOC_NR(VIDIOCGAUDIO)] = "VIDIOCGAUDIO", - [_IOC_NR(VIDIOCSAUDIO)] = "VIDIOCSAUDIO", - [_IOC_NR(VIDIOCSYNC)] = "VIDIOCSYNC", - [_IOC_NR(VIDIOCMCAPTURE)] = "VIDIOCMCAPTURE", - [_IOC_NR(VIDIOCGMBUF)] = "VIDIOCGMBUF", - [_IOC_NR(VIDIOCGUNIT)] = "VIDIOCGUNIT", - [_IOC_NR(VIDIOCGCAPTURE)] = "VIDIOCGCAPTURE", - [_IOC_NR(VIDIOCSCAPTURE)] = "VIDIOCSCAPTURE", - [_IOC_NR(VIDIOCSPLAYMODE)] = "VIDIOCSPLAYMODE", - [_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE", - [_IOC_NR(VIDIOCGPLAYINFO)] = "VIDIOCGPLAYINFO", - [_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE", - [_IOC_NR(VIDIOCGVBIFMT)] = "VIDIOCGVBIFMT", - [_IOC_NR(VIDIOCSVBIFMT)] = "VIDIOCSVBIFMT" -}; -#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls) -#endif - -static const char *v4l2_ioctls[] = { - [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP", - [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED", - [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT", - [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT", - [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT", - [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS", - [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF", - [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF", - [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF", - [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY", - [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF", - [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF", - [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON", - [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF", - [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM", - [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM", - [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD", - [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD", - [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD", - [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT", - [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL", - [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL", - [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER", - [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER", - [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO", - [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO", - [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL", - [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU", - [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT", - [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT", - [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT", - [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT", - [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT", - [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT", - [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT", - [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR", - [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR", - [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY", - [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY", - [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP", - [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP", - [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP", - [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP", - [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP", - [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD", - [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT", - [_IOC_NR(VIDIOC_ENUMAUDIO)] = "VIDIOC_ENUMAUDIO", - [_IOC_NR(VIDIOC_ENUMAUDOUT)] = "VIDIOC_ENUMAUDOUT", - [_IOC_NR(VIDIOC_G_PRIORITY)] = "VIDIOC_G_PRIORITY", - [_IOC_NR(VIDIOC_S_PRIORITY)] = "VIDIOC_S_PRIORITY", - [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP", - [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS", - [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS", - [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS", - [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS", -#if 1 - [_IOC_NR(VIDIOC_ENUM_FRAMESIZES)] = "VIDIOC_ENUM_FRAMESIZES", - [_IOC_NR(VIDIOC_ENUM_FRAMEINTERVALS)] = "VIDIOC_ENUM_FRAMEINTERVALS", - [_IOC_NR(VIDIOC_G_ENC_INDEX)] = "VIDIOC_G_ENC_INDEX", - [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD", - [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD", - - [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", - [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", - - [_IOC_NR(VIDIOC_G_CHIP_IDENT)] = "VIDIOC_G_CHIP_IDENT", - [_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK", -#endif -}; -#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) - -static const char *v4l2_int_ioctls[] = { -#ifdef CONFIG_VIDEO_V4L1_COMPAT - [_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES", - [_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS", - [_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM", - [_IOC_NR(DECODER_SET_INPUT)] = "DECODER_SET_INPUT", - [_IOC_NR(DECODER_SET_OUTPUT)] = "DECODER_SET_OUTPUT", - [_IOC_NR(DECODER_ENABLE_OUTPUT)] = "DECODER_ENABLE_OUTPUT", - [_IOC_NR(DECODER_SET_PICTURE)] = "DECODER_SET_PICTURE", - [_IOC_NR(DECODER_SET_GPIO)] = "DECODER_SET_GPIO", - [_IOC_NR(DECODER_INIT)] = "DECODER_INIT", - [_IOC_NR(DECODER_SET_VBI_BYPASS)] = "DECODER_SET_VBI_BYPASS", - [_IOC_NR(DECODER_DUMP)] = "DECODER_DUMP", -#endif - [_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO", - - [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR", - [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY", - [_IOC_NR(TUNER_SET_CONFIG)] = "TUNER_SET_CONFIG", - - [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE", - [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET", - [_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ", - [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE", - [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA", - [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA", - [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ", - [_IOC_NR(VIDIOC_INT_S_STANDBY)] = "VIDIOC_INT_S_STANDBY", - [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING", - [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING", - [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING", - [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING", - [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ", - [_IOC_NR(VIDIOC_INT_INIT)] = "VIDIOC_INT_INIT", - [_IOC_NR(VIDIOC_INT_G_STD_OUTPUT)] = "VIDIOC_INT_G_STD_OUTPUT", - [_IOC_NR(VIDIOC_INT_S_STD_OUTPUT)] = "VIDIOC_INT_S_STD_OUTPUT", -}; -#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls) - -/* Common ioctl debug function. This function can be used by - external ioctl messages as well as internal V4L ioctl */ -void v4l_printk_ioctl(unsigned int cmd) -{ - char *dir, *type; - - switch (_IOC_TYPE(cmd)) { - case 'd': - if (_IOC_NR(cmd) >= V4L2_INT_IOCTLS) { - type = "v4l2_int"; - break; - } - printk("%s", v4l2_int_ioctls[_IOC_NR(cmd)]); - return; -#ifdef CONFIG_VIDEO_V4L1_COMPAT - case 'v': - if (_IOC_NR(cmd) >= V4L1_IOCTLS) { - type = "v4l1"; - break; - } - printk("%s", v4l1_ioctls[_IOC_NR(cmd)]); - return; -#endif - case 'V': - if (_IOC_NR(cmd) >= V4L2_IOCTLS) { - type = "v4l2"; - break; - } - printk("%s", v4l2_ioctls[_IOC_NR(cmd)]); - return; - default: - type = "unknown"; - } - - switch (_IOC_DIR(cmd)) { - case _IOC_NONE: dir = "--"; break; - case _IOC_READ: dir = "r-"; break; - case _IOC_WRITE: dir = "-w"; break; - case _IOC_READ | _IOC_WRITE: dir = "rw"; break; - default: dir = "*ERR*"; break; - } - printk("%s ioctl '%c', dir=%s, #%d (0x%08x)", - type, _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd); -} -EXPORT_SYMBOL(v4l_printk_ioctl); - -/* - * sysfs stuff - */ - -static ssize_t show_index(struct device *cd, - struct device_attribute *attr, char *buf) -{ - struct video_device *vfd = container_of(cd, struct video_device, - class_dev); - return sprintf(buf, "%i\n", vfd->index); -} - -static ssize_t show_name(struct device *cd, - struct device_attribute *attr, char *buf) -{ - struct video_device *vfd = container_of(cd, struct video_device, - class_dev); - return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name); -} - -static struct device_attribute video_device_attrs[] = { - __ATTR(name, S_IRUGO, show_name, NULL), - __ATTR(index, S_IRUGO, show_index, NULL), - __ATTR_NULL -}; - -struct video_device *video_device_alloc(void) -{ - struct video_device *vfd; - - vfd = kzalloc(sizeof(*vfd),GFP_KERNEL); - return vfd; -} -EXPORT_SYMBOL(video_device_alloc); - -void video_device_release(struct video_device *vfd) -{ - kfree(vfd); -} -EXPORT_SYMBOL(video_device_release); - -static void video_release(struct device *cd) -{ - struct video_device *vfd = container_of(cd, struct video_device, - class_dev); - -#if 1 - /* needed until all drivers are fixed */ - if (!vfd->release) - return; -#endif - vfd->release(vfd); -} - -static struct class video_class = { - .name = VIDEO_NAME, - .dev_attrs = video_device_attrs, - .dev_release = video_release, -}; - -/* - * Active devices - */ - -static struct video_device *video_device[VIDEO_NUM_DEVICES]; -static DEFINE_MUTEX(videodev_lock); - -struct video_device* video_devdata(struct file *file) -{ - return video_device[iminor(file->f_path.dentry->d_inode)]; -} -EXPORT_SYMBOL(video_devdata); - -/* - * Open a video device - FIXME: Obsoleted - */ -static int video_open(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - int err = 0; - struct video_device *vfl; - const struct file_operations *old_fops; - - if(minor>=VIDEO_NUM_DEVICES) - return -ENODEV; - lock_kernel(); - mutex_lock(&videodev_lock); - vfl=video_device[minor]; - if(vfl==NULL) { - mutex_unlock(&videodev_lock); - request_module("char-major-%d-%d", VIDEO_MAJOR, minor); - mutex_lock(&videodev_lock); - vfl=video_device[minor]; - if (vfl==NULL) { - mutex_unlock(&videodev_lock); - unlock_kernel(); - return -ENODEV; - } - } - old_fops = file->f_op; - file->f_op = fops_get(vfl->fops); - if(file->f_op->open) - err = file->f_op->open(inode,file); - if (err) { - fops_put(file->f_op); - file->f_op = fops_get(old_fops); - } - fops_put(old_fops); - mutex_unlock(&videodev_lock); - unlock_kernel(); - return err; -} - -/* - * helper function -- handles userspace copying for ioctl arguments - */ - -#ifdef __OLD_VIDIOC_ -static unsigned int -video_fix_command(unsigned int cmd) -{ - switch (cmd) { - case VIDIOC_OVERLAY_OLD: - cmd = VIDIOC_OVERLAY; - break; - case VIDIOC_S_PARM_OLD: - cmd = VIDIOC_S_PARM; - break; - case VIDIOC_S_CTRL_OLD: - cmd = VIDIOC_S_CTRL; - break; - case VIDIOC_G_AUDIO_OLD: - cmd = VIDIOC_G_AUDIO; - break; - case VIDIOC_G_AUDOUT_OLD: - cmd = VIDIOC_G_AUDOUT; - break; - case VIDIOC_CROPCAP_OLD: - cmd = VIDIOC_CROPCAP; - break; - } - return cmd; -} -#endif - -/* - * Obsolete usercopy function - Should be removed soon - */ -int -video_usercopy(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, - int (*func)(struct inode *inode, struct file *file, - unsigned int cmd, void *arg)) -{ - char sbuf[128]; - void *mbuf = NULL; - void *parg = NULL; - int err = -EINVAL; - int is_ext_ctrl; - size_t ctrls_size = 0; - void __user *user_ptr = NULL; - -#ifdef __OLD_VIDIOC_ - cmd = video_fix_command(cmd); -#endif - is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || - cmd == VIDIOC_TRY_EXT_CTRLS); - - /* Copy arguments into temp kernel buffer */ - switch (_IOC_DIR(cmd)) { - case _IOC_NONE: - parg = NULL; - break; - case _IOC_READ: - case _IOC_WRITE: - case (_IOC_WRITE | _IOC_READ): - if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { - parg = sbuf; - } else { - /* too big to allocate from stack */ - mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); - if (NULL == mbuf) - return -ENOMEM; - parg = mbuf; - } - - err = -EFAULT; - if (_IOC_DIR(cmd) & _IOC_WRITE) - if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) - goto out; - break; - } - if (is_ext_ctrl) { - struct v4l2_ext_controls *p = parg; - - /* In case of an error, tell the caller that it wasn't - a specific control that caused it. */ - p->error_idx = p->count; - user_ptr = (void __user *)p->controls; - if (p->count) { - ctrls_size = sizeof(struct v4l2_ext_control) * p->count; - /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ - mbuf = kmalloc(ctrls_size, GFP_KERNEL); - err = -ENOMEM; - if (NULL == mbuf) - goto out_ext_ctrl; - err = -EFAULT; - if (copy_from_user(mbuf, user_ptr, ctrls_size)) - goto out_ext_ctrl; - p->controls = mbuf; - } - } - - /* call driver */ - err = func(inode, file, cmd, parg); - if (err == -ENOIOCTLCMD) - err = -EINVAL; - if (is_ext_ctrl) { - struct v4l2_ext_controls *p = parg; - - p->controls = (void *)user_ptr; - if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) - err = -EFAULT; - goto out_ext_ctrl; - } - if (err < 0) - goto out; - -out_ext_ctrl: - /* Copy results into user buffer */ - switch (_IOC_DIR(cmd)) - { - case _IOC_READ: - case (_IOC_WRITE | _IOC_READ): - if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) - err = -EFAULT; - break; - } - -out: - kfree(mbuf); - return err; -} -EXPORT_SYMBOL(video_usercopy); - -/* - * open/release helper functions -- handle exclusive opens - * Should be removed soon - */ -int video_exclusive_open(struct inode *inode, struct file *file) -{ - struct video_device *vfl = video_devdata(file); - int retval = 0; - - mutex_lock(&vfl->lock); - if (vfl->users) { - retval = -EBUSY; - } else { - vfl->users++; - } - mutex_unlock(&vfl->lock); - return retval; -} -EXPORT_SYMBOL(video_exclusive_open); - -int video_exclusive_release(struct inode *inode, struct file *file) -{ - struct video_device *vfl = video_devdata(file); - - vfl->users--; - return 0; -} -EXPORT_SYMBOL(video_exclusive_release); - -static void dbgbuf(unsigned int cmd, struct video_device *vfd, - struct v4l2_buffer *p) -{ - struct v4l2_timecode *tc=&p->timecode; - - dbgarg (cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, " - "bytesused=%d, flags=0x%08d, " - "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n", - (p->timestamp.tv_sec/3600), - (int)(p->timestamp.tv_sec/60)%60, - (int)(p->timestamp.tv_sec%60), - p->timestamp.tv_usec, - p->index, - prt_names(p->type, v4l2_type_names), - p->bytesused, p->flags, - p->field, p->sequence, - prt_names(p->memory, v4l2_memory_names), - p->m.userptr, p->length); - dbgarg2("timecode=%02d:%02d:%02d type=%d, " - "flags=0x%08d, frames=%d, userbits=0x%08x\n", - tc->hours,tc->minutes,tc->seconds, - tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits); -} - -static inline void dbgrect(struct video_device *vfd, char *s, - struct v4l2_rect *r) -{ - dbgarg2("%sRect start at %dx%d, size=%dx%d\n", s, r->left, r->top, - r->width, r->height); -}; - -static inline void v4l_print_pix_fmt (struct video_device *vfd, - struct v4l2_pix_format *fmt) -{ - dbgarg2 ("width=%d, height=%d, format=%c%c%c%c, field=%s, " - "bytesperline=%d sizeimage=%d, colorspace=%d\n", - fmt->width,fmt->height, - (fmt->pixelformat & 0xff), - (fmt->pixelformat >> 8) & 0xff, - (fmt->pixelformat >> 16) & 0xff, - (fmt->pixelformat >> 24) & 0xff, - prt_names(fmt->field, v4l2_field_names), - fmt->bytesperline, fmt->sizeimage, fmt->colorspace); -}; - -static inline void v4l_print_ext_ctrls(unsigned int cmd, - struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals) -{ - __u32 i; - - if (!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) - return; - dbgarg(cmd, ""); - printk(KERN_CONT "class=0x%x", c->ctrl_class); - for (i = 0; i < c->count; i++) { - if (show_vals) - printk(KERN_CONT " id/val=0x%x/0x%x", - c->controls[i].id, c->controls[i].value); - else - printk(KERN_CONT " id=0x%x", c->controls[i].id); - } - printk(KERN_CONT "\n"); -}; - -static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) -{ - __u32 i; - - /* zero the reserved fields */ - c->reserved[0] = c->reserved[1] = 0; - for (i = 0; i < c->count; i++) { - c->controls[i].reserved2[0] = 0; - c->controls[i].reserved2[1] = 0; - } - /* V4L2_CID_PRIVATE_BASE cannot be used as control class - when using extended controls. - Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL - is it allowed for backwards compatibility. - */ - if (!allow_priv && c->ctrl_class == V4L2_CID_PRIVATE_BASE) - return 0; - /* Check that all controls are from the same control class. */ - for (i = 0; i < c->count; i++) { - if (V4L2_CTRL_ID2CLASS(c->controls[i].id) != c->ctrl_class) { - c->error_idx = i; - return 0; - } - } - return 1; -} - -static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type) -{ - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (vfd->vidioc_try_fmt_vid_cap) - return (0); - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_try_fmt_vid_overlay) - return (0); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (vfd->vidioc_try_fmt_vid_out) - return (0); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_try_fmt_vid_out_overlay) - return (0); - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_try_fmt_vbi_cap) - return (0); - break; - case V4L2_BUF_TYPE_VBI_OUTPUT: - if (vfd->vidioc_try_fmt_vbi_out) - return (0); - break; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (vfd->vidioc_try_fmt_sliced_vbi_cap) - return (0); - break; - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (vfd->vidioc_try_fmt_sliced_vbi_out) - return (0); - break; - case V4L2_BUF_TYPE_PRIVATE: - if (vfd->vidioc_try_fmt_type_private) - return (0); - break; - } - return (-EINVAL); -} - -static int __video_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - struct video_device *vfd = video_devdata(file); - void *fh = file->private_data; - int ret = -EINVAL; - - if ( (vfd->debug & V4L2_DEBUG_IOCTL) && - !(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) { - v4l_print_ioctl(vfd->name, cmd); - printk("\n"); - } - -#ifdef CONFIG_VIDEO_V4L1_COMPAT - /*********************************************************** - Handles calls to the obsoleted V4L1 API - Due to the nature of VIDIOCGMBUF, each driver that supports - V4L1 should implement its own handler for this ioctl. - ***********************************************************/ - - /* --- streaming capture ------------------------------------- */ - if (cmd == VIDIOCGMBUF) { - struct video_mbuf *p=arg; - - memset(p, 0, sizeof(*p)); - - if (!vfd->vidiocgmbuf) - return ret; - ret=vfd->vidiocgmbuf(file, fh, p); - if (!ret) - dbgarg (cmd, "size=%d, frames=%d, offsets=0x%08lx\n", - p->size, p->frames, - (unsigned long)p->offsets); - return ret; - } - - /******************************************************** - All other V4L1 calls are handled by v4l1_compat module. - Those calls will be translated into V4L2 calls, and - __video_do_ioctl will be called again, with one or more - V4L2 ioctls. - ********************************************************/ - if (_IOC_TYPE(cmd)=='v') - return v4l_compat_translate_ioctl(inode,file,cmd,arg, - __video_do_ioctl); -#endif - - switch(cmd) { - /* --- capabilities ------------------------------------------ */ - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = (struct v4l2_capability*)arg; - memset(cap, 0, sizeof(*cap)); - - if (!vfd->vidioc_querycap) - break; - - ret=vfd->vidioc_querycap(file, fh, cap); - if (!ret) - dbgarg (cmd, "driver=%s, card=%s, bus=%s, " - "version=0x%08x, " - "capabilities=0x%08x\n", - cap->driver,cap->card,cap->bus_info, - cap->version, - cap->capabilities); - break; - } - - /* --- priority ------------------------------------------ */ - case VIDIOC_G_PRIORITY: - { - enum v4l2_priority *p=arg; - - if (!vfd->vidioc_g_priority) - break; - ret=vfd->vidioc_g_priority(file, fh, p); - if (!ret) - dbgarg(cmd, "priority is %d\n", *p); - break; - } - case VIDIOC_S_PRIORITY: - { - enum v4l2_priority *p=arg; - - if (!vfd->vidioc_s_priority) - break; - dbgarg(cmd, "setting priority to %d\n", *p); - ret=vfd->vidioc_s_priority(file, fh, *p); - break; - } - - /* --- capture ioctls ---------------------------------------- */ - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *f = arg; - enum v4l2_buf_type type; - unsigned int index; - - index = f->index; - type = f->type; - memset(f,0,sizeof(*f)); - f->index = index; - f->type = type; - - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (vfd->vidioc_enum_fmt_vid_cap) - ret = vfd->vidioc_enum_fmt_vid_cap(file, fh, f); - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_enum_fmt_vid_overlay) - ret = vfd->vidioc_enum_fmt_vid_overlay(file, - fh, f); - break; -#if 1 - /* V4L2_BUF_TYPE_VBI_CAPTURE should not support VIDIOC_ENUM_FMT - * according to the spec. The bttv and saa7134 drivers support - * it though, so just warn that this is deprecated and will be - * removed in the near future. */ - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_enum_fmt_vbi_cap) { - printk(KERN_WARNING "vidioc_enum_fmt_vbi_cap will be removed in 2.6.28!\n"); - ret = vfd->vidioc_enum_fmt_vbi_cap(file, fh, f); - } - break; -#endif - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (vfd->vidioc_enum_fmt_vid_out) - ret = vfd->vidioc_enum_fmt_vid_out(file, fh, f); - break; - case V4L2_BUF_TYPE_PRIVATE: - if (vfd->vidioc_enum_fmt_type_private) - ret = vfd->vidioc_enum_fmt_type_private(file, - fh, f); - break; - default: - break; - } - if (!ret) - dbgarg (cmd, "index=%d, type=%d, flags=%d, " - "pixelformat=%c%c%c%c, description='%s'\n", - f->index, f->type, f->flags, - (f->pixelformat & 0xff), - (f->pixelformat >> 8) & 0xff, - (f->pixelformat >> 16) & 0xff, - (f->pixelformat >> 24) & 0xff, - f->description); - break; - } - case VIDIOC_G_FMT: - { - struct v4l2_format *f = (struct v4l2_format *)arg; - - memset(f->fmt.raw_data, 0, sizeof(f->fmt.raw_data)); - - /* FIXME: Should be one dump per type */ - dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (vfd->vidioc_g_fmt_vid_cap) - ret = vfd->vidioc_g_fmt_vid_cap(file, fh, f); - if (!ret) - v4l_print_pix_fmt(vfd, &f->fmt.pix); - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_g_fmt_vid_overlay) - ret = vfd->vidioc_g_fmt_vid_overlay(file, - fh, f); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (vfd->vidioc_g_fmt_vid_out) - ret = vfd->vidioc_g_fmt_vid_out(file, fh, f); - if (!ret) - v4l_print_pix_fmt(vfd, &f->fmt.pix); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_g_fmt_vid_out_overlay) - ret = vfd->vidioc_g_fmt_vid_out_overlay(file, - fh, f); - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_g_fmt_vbi_cap) - ret = vfd->vidioc_g_fmt_vbi_cap(file, fh, f); - break; - case V4L2_BUF_TYPE_VBI_OUTPUT: - if (vfd->vidioc_g_fmt_vbi_out) - ret = vfd->vidioc_g_fmt_vbi_out(file, fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (vfd->vidioc_g_fmt_sliced_vbi_cap) - ret = vfd->vidioc_g_fmt_sliced_vbi_cap(file, - fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (vfd->vidioc_g_fmt_sliced_vbi_out) - ret = vfd->vidioc_g_fmt_sliced_vbi_out(file, - fh, f); - break; - case V4L2_BUF_TYPE_PRIVATE: - if (vfd->vidioc_g_fmt_type_private) - ret = vfd->vidioc_g_fmt_type_private(file, - fh, f); - break; - } - - break; - } - case VIDIOC_S_FMT: - { - struct v4l2_format *f = (struct v4l2_format *)arg; - - /* FIXME: Should be one dump per type */ - dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - v4l_print_pix_fmt(vfd, &f->fmt.pix); - if (vfd->vidioc_s_fmt_vid_cap) - ret = vfd->vidioc_s_fmt_vid_cap(file, fh, f); - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_s_fmt_vid_overlay) - ret = vfd->vidioc_s_fmt_vid_overlay(file, - fh, f); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - v4l_print_pix_fmt(vfd, &f->fmt.pix); - if (vfd->vidioc_s_fmt_vid_out) - ret = vfd->vidioc_s_fmt_vid_out(file, fh, f); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_s_fmt_vid_out_overlay) - ret = vfd->vidioc_s_fmt_vid_out_overlay(file, - fh, f); - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_s_fmt_vbi_cap) - ret = vfd->vidioc_s_fmt_vbi_cap(file, fh, f); - break; - case V4L2_BUF_TYPE_VBI_OUTPUT: - if (vfd->vidioc_s_fmt_vbi_out) - ret = vfd->vidioc_s_fmt_vbi_out(file, fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (vfd->vidioc_s_fmt_sliced_vbi_cap) - ret = vfd->vidioc_s_fmt_sliced_vbi_cap(file, - fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (vfd->vidioc_s_fmt_sliced_vbi_out) - ret = vfd->vidioc_s_fmt_sliced_vbi_out(file, - fh, f); - break; - case V4L2_BUF_TYPE_PRIVATE: - if (vfd->vidioc_s_fmt_type_private) - ret = vfd->vidioc_s_fmt_type_private(file, - fh, f); - break; - } - break; - } - case VIDIOC_TRY_FMT: - { - struct v4l2_format *f = (struct v4l2_format *)arg; - - /* FIXME: Should be one dump per type */ - dbgarg (cmd, "type=%s\n", prt_names(f->type, - v4l2_type_names)); - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (vfd->vidioc_try_fmt_vid_cap) - ret = vfd->vidioc_try_fmt_vid_cap(file, fh, f); - if (!ret) - v4l_print_pix_fmt(vfd, &f->fmt.pix); - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_try_fmt_vid_overlay) - ret = vfd->vidioc_try_fmt_vid_overlay(file, - fh, f); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (vfd->vidioc_try_fmt_vid_out) - ret = vfd->vidioc_try_fmt_vid_out(file, fh, f); - if (!ret) - v4l_print_pix_fmt(vfd, &f->fmt.pix); - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_try_fmt_vid_out_overlay) - ret = vfd->vidioc_try_fmt_vid_out_overlay(file, - fh, f); - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_try_fmt_vbi_cap) - ret = vfd->vidioc_try_fmt_vbi_cap(file, fh, f); - break; - case V4L2_BUF_TYPE_VBI_OUTPUT: - if (vfd->vidioc_try_fmt_vbi_out) - ret = vfd->vidioc_try_fmt_vbi_out(file, fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (vfd->vidioc_try_fmt_sliced_vbi_cap) - ret = vfd->vidioc_try_fmt_sliced_vbi_cap(file, - fh, f); - break; - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (vfd->vidioc_try_fmt_sliced_vbi_out) - ret = vfd->vidioc_try_fmt_sliced_vbi_out(file, - fh, f); - break; - case V4L2_BUF_TYPE_PRIVATE: - if (vfd->vidioc_try_fmt_type_private) - ret = vfd->vidioc_try_fmt_type_private(file, - fh, f); - break; - } - - break; - } - /* FIXME: Those buf reqs could be handled here, - with some changes on videobuf to allow its header to be included at - videodev2.h or being merged at videodev2. - */ - case VIDIOC_REQBUFS: - { - struct v4l2_requestbuffers *p=arg; - - if (!vfd->vidioc_reqbufs) - break; - ret = check_fmt (vfd, p->type); - if (ret) - break; - - ret=vfd->vidioc_reqbufs(file, fh, p); - dbgarg (cmd, "count=%d, type=%s, memory=%s\n", - p->count, - prt_names(p->type, v4l2_type_names), - prt_names(p->memory, v4l2_memory_names)); - break; - } - case VIDIOC_QUERYBUF: - { - struct v4l2_buffer *p=arg; - - if (!vfd->vidioc_querybuf) - break; - ret = check_fmt (vfd, p->type); - if (ret) - break; - - ret=vfd->vidioc_querybuf(file, fh, p); - if (!ret) - dbgbuf(cmd,vfd,p); - break; - } - case VIDIOC_QBUF: - { - struct v4l2_buffer *p=arg; - - if (!vfd->vidioc_qbuf) - break; - ret = check_fmt (vfd, p->type); - if (ret) - break; - - ret=vfd->vidioc_qbuf(file, fh, p); - if (!ret) - dbgbuf(cmd,vfd,p); - break; - } - case VIDIOC_DQBUF: - { - struct v4l2_buffer *p=arg; - if (!vfd->vidioc_dqbuf) - break; - ret = check_fmt (vfd, p->type); - if (ret) - break; - - ret=vfd->vidioc_dqbuf(file, fh, p); - if (!ret) - dbgbuf(cmd,vfd,p); - break; - } - case VIDIOC_OVERLAY: - { - int *i = arg; - - if (!vfd->vidioc_overlay) - break; - dbgarg (cmd, "value=%d\n",*i); - ret=vfd->vidioc_overlay(file, fh, *i); - break; - } - case VIDIOC_G_FBUF: - { - struct v4l2_framebuffer *p = arg; - - if (!vfd->vidioc_g_fbuf) - break; - ret = vfd->vidioc_g_fbuf(file, fh, arg); - if (!ret) { - dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", - p->capability, p->flags, - (unsigned long)p->base); - v4l_print_pix_fmt(vfd, &p->fmt); - } - break; - } - case VIDIOC_S_FBUF: - { - struct v4l2_framebuffer *p = arg; - - if (!vfd->vidioc_s_fbuf) - break; - dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", - p->capability, p->flags, (unsigned long)p->base); - v4l_print_pix_fmt(vfd, &p->fmt); - ret = vfd->vidioc_s_fbuf(file, fh, arg); - break; - } - case VIDIOC_STREAMON: - { - enum v4l2_buf_type i = *(int *)arg; - if (!vfd->vidioc_streamon) - break; - dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); - ret=vfd->vidioc_streamon(file, fh,i); - break; - } - case VIDIOC_STREAMOFF: - { - enum v4l2_buf_type i = *(int *)arg; - - if (!vfd->vidioc_streamoff) - break; - dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); - ret=vfd->vidioc_streamoff(file, fh, i); - break; - } - /* ---------- tv norms ---------- */ - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *p = arg; - v4l2_std_id id = vfd->tvnorms, curr_id = 0; - unsigned int index = p->index, i, j = 0; - const char *descr = ""; - - /* Return norm array in a canonical way */ - for (i = 0; i <= index && id; i++) { - /* last std value in the standards array is 0, so this - while always ends there since (id & 0) == 0. */ - while ((id & standards[j].std) != standards[j].std) - j++; - curr_id = standards[j].std; - descr = standards[j].descr; - j++; - if (curr_id == 0) - break; - if (curr_id != V4L2_STD_PAL && - curr_id != V4L2_STD_SECAM && - curr_id != V4L2_STD_NTSC) - id &= ~curr_id; - } - if (i <= index) - return -EINVAL; - - v4l2_video_std_construct(p, curr_id, descr); - p->index = index; - - dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, " - "framelines=%d\n", p->index, - (unsigned long long)p->id, p->name, - p->frameperiod.numerator, - p->frameperiod.denominator, - p->framelines); - - ret = 0; - break; - } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; - - ret = 0; - /* Calls the specific handler */ - if (vfd->vidioc_g_std) - ret = vfd->vidioc_g_std(file, fh, id); - else - *id = vfd->current_norm; - - if (!ret) - dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id); - break; - } - case VIDIOC_S_STD: - { - v4l2_std_id *id = arg,norm; - - dbgarg(cmd, "std=%08Lx\n", (long long unsigned)*id); - - norm = (*id) & vfd->tvnorms; - if ( vfd->tvnorms && !norm) /* Check if std is supported */ - break; - - /* Calls the specific handler */ - if (vfd->vidioc_s_std) - ret=vfd->vidioc_s_std(file, fh, &norm); - else - ret=-EINVAL; - - /* Updates standard information */ - if (ret>=0) - vfd->current_norm=norm; - - break; - } - case VIDIOC_QUERYSTD: - { - v4l2_std_id *p=arg; - - if (!vfd->vidioc_querystd) - break; - ret=vfd->vidioc_querystd(file, fh, arg); - if (!ret) - dbgarg (cmd, "detected std=%08Lx\n", - (unsigned long long)*p); - break; - } - /* ------ input switching ---------- */ - /* FIXME: Inputs can be handled inside videodev2 */ - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *p=arg; - int i=p->index; - - if (!vfd->vidioc_enum_input) - break; - memset(p, 0, sizeof(*p)); - p->index=i; - - ret=vfd->vidioc_enum_input(file, fh, p); - if (!ret) - dbgarg (cmd, "index=%d, name=%s, type=%d, " - "audioset=%d, " - "tuner=%d, std=%08Lx, status=%d\n", - p->index,p->name,p->type,p->audioset, - p->tuner, - (unsigned long long)p->std, - p->status); - break; - } - case VIDIOC_G_INPUT: - { - unsigned int *i = arg; - - if (!vfd->vidioc_g_input) - break; - ret=vfd->vidioc_g_input(file, fh, i); - if (!ret) - dbgarg (cmd, "value=%d\n",*i); - break; - } - case VIDIOC_S_INPUT: - { - unsigned int *i = arg; - - if (!vfd->vidioc_s_input) - break; - dbgarg (cmd, "value=%d\n",*i); - ret=vfd->vidioc_s_input(file, fh, *i); - break; - } - - /* ------ output switching ---------- */ - case VIDIOC_ENUMOUTPUT: - { - struct v4l2_output *p = arg; - int i = p->index; - - if (!vfd->vidioc_enum_output) - break; - memset(p, 0, sizeof(*p)); - p->index = i; - - ret = vfd->vidioc_enum_output(file, fh, p); - if (!ret) - dbgarg(cmd, "index=%d, name=%s, type=%d, " - "audioset=0x%x, " - "modulator=%d, std=0x%08Lx\n", - p->index, p->name, p->type, p->audioset, - p->modulator, (unsigned long long)p->std); - break; - } - case VIDIOC_G_OUTPUT: - { - unsigned int *i = arg; - - if (!vfd->vidioc_g_output) - break; - ret=vfd->vidioc_g_output(file, fh, i); - if (!ret) - dbgarg (cmd, "value=%d\n",*i); - break; - } - case VIDIOC_S_OUTPUT: - { - unsigned int *i = arg; - - if (!vfd->vidioc_s_output) - break; - dbgarg (cmd, "value=%d\n",*i); - ret=vfd->vidioc_s_output(file, fh, *i); - break; - } - - /* --- controls ---------------------------------------------- */ - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *p = arg; - - if (!vfd->vidioc_queryctrl) - break; - ret = vfd->vidioc_queryctrl(file, fh, p); - if (!ret) - dbgarg(cmd, "id=0x%x, type=%d, name=%s, min/max=%d/%d, " - "step=%d, default=%d, flags=0x%08x\n", - p->id, p->type, p->name, - p->minimum, p->maximum, - p->step, p->default_value, p->flags); - else - dbgarg(cmd, "id=0x%x\n", p->id); - break; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *p = arg; - - if (vfd->vidioc_g_ctrl) - ret = vfd->vidioc_g_ctrl(file, fh, p); - else if (vfd->vidioc_g_ext_ctrls) { - struct v4l2_ext_controls ctrls; - struct v4l2_ext_control ctrl; - - ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); - ctrls.count = 1; - ctrls.controls = &ctrl; - ctrl.id = p->id; - ctrl.value = p->value; - if (check_ext_ctrls(&ctrls, 1)) { - ret = vfd->vidioc_g_ext_ctrls(file, fh, &ctrls); - if (ret == 0) - p->value = ctrl.value; - } - } else - break; - if (!ret) - dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); - else - dbgarg(cmd, "id=0x%x\n", p->id); - break; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *p = arg; - struct v4l2_ext_controls ctrls; - struct v4l2_ext_control ctrl; - - if (!vfd->vidioc_s_ctrl && !vfd->vidioc_s_ext_ctrls) - break; - - dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); - - if (vfd->vidioc_s_ctrl) { - ret = vfd->vidioc_s_ctrl(file, fh, p); - break; - } - if (!vfd->vidioc_s_ext_ctrls) - break; - - ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); - ctrls.count = 1; - ctrls.controls = &ctrl; - ctrl.id = p->id; - ctrl.value = p->value; - if (check_ext_ctrls(&ctrls, 1)) - ret = vfd->vidioc_s_ext_ctrls(file, fh, &ctrls); - break; - } - case VIDIOC_G_EXT_CTRLS: - { - struct v4l2_ext_controls *p = arg; - - p->error_idx = p->count; - if (!vfd->vidioc_g_ext_ctrls) - break; - if (check_ext_ctrls(p, 0)) - ret = vfd->vidioc_g_ext_ctrls(file, fh, p); - v4l_print_ext_ctrls(cmd, vfd, p, !ret); - break; - } - case VIDIOC_S_EXT_CTRLS: - { - struct v4l2_ext_controls *p = arg; - - p->error_idx = p->count; - if (!vfd->vidioc_s_ext_ctrls) - break; - v4l_print_ext_ctrls(cmd, vfd, p, 1); - if (check_ext_ctrls(p, 0)) - ret = vfd->vidioc_s_ext_ctrls(file, fh, p); - break; - } - case VIDIOC_TRY_EXT_CTRLS: - { - struct v4l2_ext_controls *p = arg; - - p->error_idx = p->count; - if (!vfd->vidioc_try_ext_ctrls) - break; - v4l_print_ext_ctrls(cmd, vfd, p, 1); - if (check_ext_ctrls(p, 0)) - ret = vfd->vidioc_try_ext_ctrls(file, fh, p); - break; - } - case VIDIOC_QUERYMENU: - { - struct v4l2_querymenu *p = arg; - - if (!vfd->vidioc_querymenu) - break; - ret = vfd->vidioc_querymenu(file, fh, p); - if (!ret) - dbgarg(cmd, "id=0x%x, index=%d, name=%s\n", - p->id, p->index, p->name); - else - dbgarg(cmd, "id=0x%x, index=%d\n", - p->id, p->index); - break; - } - /* --- audio ---------------------------------------------- */ - case VIDIOC_ENUMAUDIO: - { - struct v4l2_audio *p = arg; - - if (!vfd->vidioc_enumaudio) - break; - ret = vfd->vidioc_enumaudio(file, fh, p); - if (!ret) - dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " - "mode=0x%x\n", p->index, p->name, - p->capability, p->mode); - else - dbgarg(cmd, "index=%d\n", p->index); - break; - } - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *p = arg; - __u32 index = p->index; - - if (!vfd->vidioc_g_audio) - break; - - memset(p, 0, sizeof(*p)); - p->index = index; - ret = vfd->vidioc_g_audio(file, fh, p); - if (!ret) - dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " - "mode=0x%x\n", p->index, - p->name, p->capability, p->mode); - else - dbgarg(cmd, "index=%d\n", p->index); - break; - } - case VIDIOC_S_AUDIO: - { - struct v4l2_audio *p = arg; - - if (!vfd->vidioc_s_audio) - break; - dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " - "mode=0x%x\n", p->index, p->name, - p->capability, p->mode); - ret = vfd->vidioc_s_audio(file, fh, p); - break; - } - case VIDIOC_ENUMAUDOUT: - { - struct v4l2_audioout *p=arg; - - if (!vfd->vidioc_enumaudout) - break; - dbgarg(cmd, "Enum for index=%d\n", p->index); - ret=vfd->vidioc_enumaudout(file, fh, p); - if (!ret) - dbgarg2("index=%d, name=%s, capability=%d, " - "mode=%d\n", p->index, p->name, - p->capability,p->mode); - break; - } - case VIDIOC_G_AUDOUT: - { - struct v4l2_audioout *p=arg; - - if (!vfd->vidioc_g_audout) - break; - dbgarg(cmd, "Enum for index=%d\n", p->index); - ret=vfd->vidioc_g_audout(file, fh, p); - if (!ret) - dbgarg2("index=%d, name=%s, capability=%d, " - "mode=%d\n", p->index, p->name, - p->capability,p->mode); - break; - } - case VIDIOC_S_AUDOUT: - { - struct v4l2_audioout *p=arg; - - if (!vfd->vidioc_s_audout) - break; - dbgarg(cmd, "index=%d, name=%s, capability=%d, " - "mode=%d\n", p->index, p->name, - p->capability,p->mode); - - ret=vfd->vidioc_s_audout(file, fh, p); - break; - } - case VIDIOC_G_MODULATOR: - { - struct v4l2_modulator *p=arg; - if (!vfd->vidioc_g_modulator) - break; - ret=vfd->vidioc_g_modulator(file, fh, p); - if (!ret) - dbgarg(cmd, "index=%d, name=%s, " - "capability=%d, rangelow=%d," - " rangehigh=%d, txsubchans=%d\n", - p->index, p->name,p->capability, - p->rangelow, p->rangehigh, - p->txsubchans); - break; - } - case VIDIOC_S_MODULATOR: - { - struct v4l2_modulator *p=arg; - if (!vfd->vidioc_s_modulator) - break; - dbgarg(cmd, "index=%d, name=%s, capability=%d, " - "rangelow=%d, rangehigh=%d, txsubchans=%d\n", - p->index, p->name,p->capability,p->rangelow, - p->rangehigh,p->txsubchans); - ret=vfd->vidioc_s_modulator(file, fh, p); - break; - } - case VIDIOC_G_CROP: - { - struct v4l2_crop *p=arg; - if (!vfd->vidioc_g_crop) - break; - dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - ret=vfd->vidioc_g_crop(file, fh, p); - if (!ret) { - dbgrect(vfd, "", &p->c); - } - break; - } - case VIDIOC_S_CROP: - { - struct v4l2_crop *p=arg; - if (!vfd->vidioc_s_crop) - break; - dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - dbgrect(vfd, "", &p->c); - ret=vfd->vidioc_s_crop(file, fh, p); - break; - } - case VIDIOC_CROPCAP: - { - struct v4l2_cropcap *p = arg; - - /*FIXME: Should also show v4l2_fract pixelaspect */ - if (!vfd->vidioc_cropcap) - break; - dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - ret = vfd->vidioc_cropcap(file, fh, p); - if (!ret) { - dbgrect(vfd, "bounds ", &p->bounds); - dbgrect(vfd, "defrect ", &p->defrect); - } - break; - } - case VIDIOC_G_JPEGCOMP: - { - struct v4l2_jpegcompression *p=arg; - if (!vfd->vidioc_g_jpegcomp) - break; - ret=vfd->vidioc_g_jpegcomp(file, fh, p); - if (!ret) - dbgarg (cmd, "quality=%d, APPn=%d, " - "APP_len=%d, COM_len=%d, " - "jpeg_markers=%d\n", - p->quality,p->APPn,p->APP_len, - p->COM_len,p->jpeg_markers); - break; - } - case VIDIOC_S_JPEGCOMP: - { - struct v4l2_jpegcompression *p=arg; - if (!vfd->vidioc_g_jpegcomp) - break; - dbgarg (cmd, "quality=%d, APPn=%d, APP_len=%d, " - "COM_len=%d, jpeg_markers=%d\n", - p->quality,p->APPn,p->APP_len, - p->COM_len,p->jpeg_markers); - ret=vfd->vidioc_s_jpegcomp(file, fh, p); - break; - } - case VIDIOC_G_ENC_INDEX: - { - struct v4l2_enc_idx *p=arg; - - if (!vfd->vidioc_g_enc_index) - break; - ret=vfd->vidioc_g_enc_index(file, fh, p); - if (!ret) - dbgarg (cmd, "entries=%d, entries_cap=%d\n", - p->entries,p->entries_cap); - break; - } - case VIDIOC_ENCODER_CMD: - { - struct v4l2_encoder_cmd *p = arg; - - if (!vfd->vidioc_encoder_cmd) - break; - memset(&p->raw, 0, sizeof(p->raw)); - ret = vfd->vidioc_encoder_cmd(file, fh, p); - if (!ret) - dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); - break; - } - case VIDIOC_TRY_ENCODER_CMD: - { - struct v4l2_encoder_cmd *p = arg; - - if (!vfd->vidioc_try_encoder_cmd) - break; - memset(&p->raw, 0, sizeof(p->raw)); - ret = vfd->vidioc_try_encoder_cmd(file, fh, p); - if (!ret) - dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); - break; - } - case VIDIOC_G_PARM: - { - struct v4l2_streamparm *p=arg; - __u32 type=p->type; - - memset(p,0,sizeof(*p)); - p->type=type; - - if (vfd->vidioc_g_parm) { - ret=vfd->vidioc_g_parm(file, fh, p); - } else { - struct v4l2_standard s; - - if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - v4l2_video_std_construct(&s, vfd->current_norm, - v4l2_norm_to_name(vfd->current_norm)); - - p->parm.capture.timeperframe = s.frameperiod; - ret=0; - } - - dbgarg (cmd, "type=%d\n", p->type); - break; - } - case VIDIOC_S_PARM: - { - struct v4l2_streamparm *p=arg; - if (!vfd->vidioc_s_parm) - break; - dbgarg (cmd, "type=%d\n", p->type); - ret=vfd->vidioc_s_parm(file, fh, p); - break; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *p = arg; - __u32 index = p->index; - - if (!vfd->vidioc_g_tuner) - break; - - memset(p, 0, sizeof(*p)); - p->index = index; - - ret = vfd->vidioc_g_tuner(file, fh, p); - if (!ret) - dbgarg(cmd, "index=%d, name=%s, type=%d, " - "capability=0x%x, rangelow=%d, " - "rangehigh=%d, signal=%d, afc=%d, " - "rxsubchans=0x%x, audmode=%d\n", - p->index, p->name, p->type, - p->capability, p->rangelow, - p->rangehigh, p->signal, p->afc, - p->rxsubchans, p->audmode); - break; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *p = arg; - - if (!vfd->vidioc_s_tuner) - break; - dbgarg(cmd, "index=%d, name=%s, type=%d, " - "capability=0x%x, rangelow=%d, " - "rangehigh=%d, signal=%d, afc=%d, " - "rxsubchans=0x%x, audmode=%d\n", - p->index, p->name, p->type, - p->capability, p->rangelow, - p->rangehigh, p->signal, p->afc, - p->rxsubchans, p->audmode); - ret = vfd->vidioc_s_tuner(file, fh, p); - break; - } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *p = arg; - - if (!vfd->vidioc_g_frequency) - break; - - memset(p->reserved, 0, sizeof(p->reserved)); - - ret = vfd->vidioc_g_frequency(file, fh, p); - if (!ret) - dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", - p->tuner, p->type, p->frequency); - break; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *p=arg; - if (!vfd->vidioc_s_frequency) - break; - dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n", - p->tuner,p->type,p->frequency); - ret=vfd->vidioc_s_frequency(file, fh, p); - break; - } - case VIDIOC_G_SLICED_VBI_CAP: - { - struct v4l2_sliced_vbi_cap *p = arg; - __u32 type = p->type; - - if (!vfd->vidioc_g_sliced_vbi_cap) - break; - memset(p, 0, sizeof(*p)); - p->type = type; - dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - ret = vfd->vidioc_g_sliced_vbi_cap(file, fh, p); - if (!ret) - dbgarg2("service_set=%d\n", p->service_set); - break; - } - case VIDIOC_LOG_STATUS: - { - if (!vfd->vidioc_log_status) - break; - ret=vfd->vidioc_log_status(file, fh); - break; - } -#ifdef CONFIG_VIDEO_ADV_DEBUG - case VIDIOC_DBG_G_REGISTER: - { - struct v4l2_register *p=arg; - if (!capable(CAP_SYS_ADMIN)) - ret=-EPERM; - else if (vfd->vidioc_g_register) - ret=vfd->vidioc_g_register(file, fh, p); - break; - } - case VIDIOC_DBG_S_REGISTER: - { - struct v4l2_register *p=arg; - if (!capable(CAP_SYS_ADMIN)) - ret=-EPERM; - else if (vfd->vidioc_s_register) - ret=vfd->vidioc_s_register(file, fh, p); - break; - } -#endif - case VIDIOC_G_CHIP_IDENT: - { - struct v4l2_chip_ident *p=arg; - if (!vfd->vidioc_g_chip_ident) - break; - ret=vfd->vidioc_g_chip_ident(file, fh, p); - if (!ret) - dbgarg (cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision); - break; - } - default: - { - if (!vfd->vidioc_default) - break; - ret = vfd->vidioc_default(file, fh, cmd, arg); - break; - } - case VIDIOC_S_HW_FREQ_SEEK: - { - struct v4l2_hw_freq_seek *p = arg; - if (!vfd->vidioc_s_hw_freq_seek) - break; - dbgarg(cmd, - "tuner=%d, type=%d, seek_upward=%d, wrap_around=%d\n", - p->tuner, p->type, p->seek_upward, p->wrap_around); - ret = vfd->vidioc_s_hw_freq_seek(file, fh, p); - break; - } - } /* switch */ - - if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { - if (ret < 0) { - v4l_print_ioctl(vfd->name, cmd); - printk(KERN_CONT " error %d\n", ret); - } - } - - return ret; -} - -int video_ioctl2 (struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - char sbuf[128]; - void *mbuf = NULL; - void *parg = NULL; - int err = -EINVAL; - int is_ext_ctrl; - size_t ctrls_size = 0; - void __user *user_ptr = NULL; - -#ifdef __OLD_VIDIOC_ - cmd = video_fix_command(cmd); -#endif - is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || - cmd == VIDIOC_TRY_EXT_CTRLS); - - /* Copy arguments into temp kernel buffer */ - switch (_IOC_DIR(cmd)) { - case _IOC_NONE: - parg = NULL; - break; - case _IOC_READ: - case _IOC_WRITE: - case (_IOC_WRITE | _IOC_READ): - if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { - parg = sbuf; - } else { - /* too big to allocate from stack */ - mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); - if (NULL == mbuf) - return -ENOMEM; - parg = mbuf; - } - - err = -EFAULT; - if (_IOC_DIR(cmd) & _IOC_WRITE) - if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) - goto out; - break; - } - - if (is_ext_ctrl) { - struct v4l2_ext_controls *p = parg; - - /* In case of an error, tell the caller that it wasn't - a specific control that caused it. */ - p->error_idx = p->count; - user_ptr = (void __user *)p->controls; - if (p->count) { - ctrls_size = sizeof(struct v4l2_ext_control) * p->count; - /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ - mbuf = kmalloc(ctrls_size, GFP_KERNEL); - err = -ENOMEM; - if (NULL == mbuf) - goto out_ext_ctrl; - err = -EFAULT; - if (copy_from_user(mbuf, user_ptr, ctrls_size)) - goto out_ext_ctrl; - p->controls = mbuf; - } - } - - /* Handles IOCTL */ - err = __video_do_ioctl(inode, file, cmd, parg); - if (err == -ENOIOCTLCMD) - err = -EINVAL; - if (is_ext_ctrl) { - struct v4l2_ext_controls *p = parg; - - p->controls = (void *)user_ptr; - if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) - err = -EFAULT; - goto out_ext_ctrl; - } - if (err < 0) - goto out; - -out_ext_ctrl: - /* Copy results into user buffer */ - switch (_IOC_DIR(cmd)) - { - case _IOC_READ: - case (_IOC_WRITE | _IOC_READ): - if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) - err = -EFAULT; - break; - } - -out: - kfree(mbuf); - return err; -} -EXPORT_SYMBOL(video_ioctl2); - -/** - * get_index - assign stream number based on parent device - * @vdev: video_device to assign index number to, vdev->dev should be assigned - * @num: -1 if auto assign, requested number otherwise - * - * - * returns -ENFILE if num is already in use, a free index number if - * successful. - */ -static int get_index(struct video_device *vdev, int num) -{ - u32 used = 0; - const int max_index = sizeof(used) * 8 - 1; - int i; - - /* Currently a single v4l driver instance cannot create more than - 32 devices. - Increase to u64 or an array of u32 if more are needed. */ - if (num > max_index) { - printk(KERN_ERR "videodev: %s num is too large\n", __func__); - return -EINVAL; - } - - for (i = 0; i < VIDEO_NUM_DEVICES; i++) { - if (video_device[i] != NULL && - video_device[i] != vdev && - video_device[i]->dev == vdev->dev) { - used |= 1 << video_device[i]->index; - } - } - - if (num >= 0) { - if (used & (1 << num)) - return -ENFILE; - return num; - } - - i = ffz(used); - return i > max_index ? -ENFILE : i; -} - -static const struct file_operations video_fops; - -int video_register_device(struct video_device *vfd, int type, int nr) -{ - return video_register_device_index(vfd, type, nr, -1); -} -EXPORT_SYMBOL(video_register_device); - -/** - * video_register_device - register video4linux devices - * @vfd: video device structure we want to register - * @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 - * driver initialize function is called (if non %NULL). - * - * Zero is returned on success. - * - * Valid types are - * - * %VFL_TYPE_GRABBER - A frame grabber - * - * %VFL_TYPE_VTX - A teletext device - * - * %VFL_TYPE_VBI - Vertical blank data (undecoded) - * - * %VFL_TYPE_RADIO - A radio card - */ - -int video_register_device_index(struct video_device *vfd, int type, int nr, - int index) -{ - int i=0; - int base; - int end; - int ret; - char *name_base; - - switch(type) - { - case VFL_TYPE_GRABBER: - base=MINOR_VFL_TYPE_GRABBER_MIN; - end=MINOR_VFL_TYPE_GRABBER_MAX+1; - name_base = "video"; - break; - case VFL_TYPE_VTX: - base=MINOR_VFL_TYPE_VTX_MIN; - end=MINOR_VFL_TYPE_VTX_MAX+1; - name_base = "vtx"; - break; - case VFL_TYPE_VBI: - base=MINOR_VFL_TYPE_VBI_MIN; - end=MINOR_VFL_TYPE_VBI_MAX+1; - name_base = "vbi"; - break; - case VFL_TYPE_RADIO: - base=MINOR_VFL_TYPE_RADIO_MIN; - end=MINOR_VFL_TYPE_RADIO_MAX+1; - name_base = "radio"; - break; - default: - printk(KERN_ERR "%s called with unknown type: %d\n", - __func__, type); - return -1; - } - - /* pick a minor number */ - mutex_lock(&videodev_lock); - if (nr >= 0 && nr < end-base) { - /* use the one the driver asked for */ - i = base+nr; - if (NULL != video_device[i]) { - mutex_unlock(&videodev_lock); - return -ENFILE; - } - } else { - /* use first free */ - for(i=base;iminor=i; - - ret = get_index(vfd, index); - vfd->index = ret; - - mutex_unlock(&videodev_lock); - - if (ret < 0) { - printk(KERN_ERR "%s: get_index failed\n", __func__); - goto fail_minor; - } - - mutex_init(&vfd->lock); - - /* sysfs class */ - memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev)); - vfd->class_dev.class = &video_class; - vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); - if (vfd->dev) - vfd->class_dev.parent = vfd->dev; - sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base); - ret = device_register(&vfd->class_dev); - if (ret < 0) { - printk(KERN_ERR "%s: device_register failed\n", __func__); - goto fail_minor; - } - -#if 1 - /* needed until all drivers are fixed */ - if (!vfd->release) - printk(KERN_WARNING "videodev: \"%s\" has no release callback. " - "Please fix your driver for proper sysfs support, see " - "http://lwn.net/Articles/36850/\n", vfd->name); -#endif - return 0; - -fail_minor: - mutex_lock(&videodev_lock); - video_device[vfd->minor] = NULL; - vfd->minor = -1; - mutex_unlock(&videodev_lock); - return ret; -} -EXPORT_SYMBOL(video_register_device_index); - -/** - * video_unregister_device - unregister a video4linux device - * @vfd: the device to unregister - * - * 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) -{ - mutex_lock(&videodev_lock); - if(video_device[vfd->minor]!=vfd) - panic("videodev: bad unregister"); - - video_device[vfd->minor]=NULL; - device_unregister(&vfd->class_dev); - mutex_unlock(&videodev_lock); -} -EXPORT_SYMBOL(video_unregister_device); - -/* - * Video fs operations - */ -static const struct file_operations video_fops= -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .open = video_open, -}; - -/* - * Initialise video for linux - */ - -static int __init videodev_init(void) -{ - int ret; - - printk(KERN_INFO "Linux video capture interface: v2.00\n"); - if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) { - printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR); - return -EIO; - } - - ret = class_register(&video_class); - if (ret < 0) { - unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME); - printk(KERN_WARNING "video_dev: class_register failed\n"); - return -EIO; - } - - return 0; -} - -static void __exit videodev_exit(void) -{ - class_unregister(&video_class); - unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME); -} - -module_init(videodev_init) -module_exit(videodev_exit) - -MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab "); -MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2"); -MODULE_LICENSE("GPL"); - - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ -- cgit v1.2.3 From 5e85e732f0ed56aa97a3ba26ac2b93ffe597a208 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 20 Jul 2008 06:31:39 -0300 Subject: V4L/DVB (8428): videodev: rename 'dev' to 'parent' The field 'dev' is not the video device, but the parent of the video device. Rename accordingly. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 4 ++-- drivers/media/video/cafe_ccic.c | 2 +- drivers/media/video/cx18/cx18-streams.c | 2 +- drivers/media/video/cx23885/cx23885-417.c | 2 +- drivers/media/video/cx23885/cx23885-video.c | 2 +- drivers/media/video/cx88/cx88-core.c | 2 +- drivers/media/video/em28xx/em28xx-video.c | 2 +- drivers/media/video/gspca/gspca.c | 2 +- drivers/media/video/ivtv/ivtv-streams.c | 2 +- drivers/media/video/meye.c | 2 +- drivers/media/video/mt9m001.c | 2 +- drivers/media/video/ov511.c | 2 +- drivers/media/video/pwc/pwc-if.c | 2 +- drivers/media/video/s2255drv.c | 2 +- drivers/media/video/saa7134/saa7134-core.c | 2 +- drivers/media/video/saa7134/saa7134-empress.c | 2 +- drivers/media/video/soc_camera.c | 10 +++++----- drivers/media/video/stk-webcam.c | 2 +- drivers/media/video/stv680.c | 2 +- drivers/media/video/usbvideo/usbvideo.c | 2 +- drivers/media/video/usbvision/usbvision-video.c | 2 +- drivers/media/video/uvc/uvc_driver.c | 2 +- drivers/media/video/v4l2-dev.c | 6 +++--- drivers/media/video/w9968cf.c | 2 +- 24 files changed, 31 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 0ea559a7fe5..3dda84d115d 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -164,7 +164,7 @@ static ssize_t show_card(struct device *cd, struct device_attribute *attr, char *buf) { struct video_device *vfd = container_of(cd, struct video_device, class_dev); - struct bttv *btv = dev_get_drvdata(vfd->dev); + struct bttv *btv = dev_get_drvdata(vfd->parent); return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET); } static DEVICE_ATTR(card, S_IRUGO, show_card, NULL); @@ -4185,7 +4185,7 @@ static struct video_device *vdev_init(struct bttv *btv, return NULL; *vfd = *template; vfd->minor = -1; - vfd->dev = &btv->c.pci->dev; + vfd->parent = &btv->c.pci->dev; vfd->release = video_device_release; vfd->type = type; vfd->debug = bttv_debug; diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index d99453faaab..ebcc8ad6271 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -2157,7 +2157,7 @@ static int cafe_pci_probe(struct pci_dev *pdev, cam->v4ldev = cafe_v4l_template; cam->v4ldev.debug = 0; // cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG; - cam->v4ldev.dev = &pdev->dev; + cam->v4ldev.parent = &pdev->dev; ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1); if (ret) goto out_smbus; diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 1728b1d832a..210a2416b32 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -194,7 +194,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type) cx->num); s->v4l2dev->minor = minor; - s->v4l2dev->dev = &cx->dev->dev; + s->v4l2dev->parent = &cx->dev->dev; s->v4l2dev->fops = cx18_stream_info[type].fops; s->v4l2dev->release = video_device_release; s->v4l2dev->tvnorms = V4L2_STD_ALL; diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index e7ef093265a..1b252976eda 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -1766,7 +1766,7 @@ static struct video_device *cx23885_video_dev_alloc( vfd->minor = -1; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, cx23885_boards[tsport->dev->board].name); - vfd->dev = &pci->dev; + vfd->parent = &pci->dev; vfd->release = video_device_release; return vfd; } diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 043fc4e5c58..3b807ba874f 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -326,7 +326,7 @@ struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, return NULL; *vfd = *template; vfd->minor = -1; - vfd->dev = &pci->dev; + vfd->parent = &pci->dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, cx23885_boards[dev->board].name); diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 60eeda3057e..2c0582e0559 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1006,7 +1006,7 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, return NULL; *vfd = *template; vfd->minor = -1; - vfd->dev = &pci->dev; + vfd->parent = &pci->dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", core->name, type, core->board.name); diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 2d9f14d2a00..838e7ecfd86 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1892,7 +1892,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, return NULL; *vfd = *template; vfd->minor = -1; - vfd->dev = &dev->udev->dev; + vfd->parent = &dev->udev->dev; vfd->release = video_device_release; vfd->type = type; vfd->debug = video_debug; diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 16e367cec76..f5b77deab72 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -1740,7 +1740,7 @@ int gspca_dev_probe(struct usb_interface *intf, /* init video stuff */ memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template); - gspca_dev->vdev.dev = &dev->dev; + gspca_dev->vdev.parent = &dev->dev; memcpy(&gspca_dev->fops, &dev_fops, sizeof gspca_dev->fops); gspca_dev->vdev.fops = &gspca_dev->fops; gspca_dev->fops.owner = module; /* module protection */ diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index f8883b487f4..b883c4e08fb 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -217,7 +217,7 @@ static int ivtv_prep_dev(struct ivtv *itv, int type) itv->num, s->name); s->v4l2dev->minor = minor; - s->v4l2dev->dev = &itv->dev->dev; + s->v4l2dev->parent = &itv->dev->dev; s->v4l2dev->fops = ivtv_stream_info[type].fops; s->v4l2dev->release = video_device_release; s->v4l2dev->tvnorms = V4L2_STD_ALL; diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index 2fb5854cf6f..0045367a66f 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -1801,7 +1801,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev, } memcpy(meye.video_dev, &meye_template, sizeof(meye_template)); - meye.video_dev->dev = &meye.mchip_dev->dev; + meye.video_dev->parent = &meye.mchip_dev->dev; if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) { printk(KERN_ERR "meye: unable to power on the camera\n"); diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index ee43499544c..554d2295484 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -120,7 +120,7 @@ static int mt9m001_init(struct soc_camera_device *icd) int ret; /* Disable chip, synchronous option update */ - dev_dbg(icd->vdev->dev, "%s\n", __func__); + dev_dbg(icd->vdev->parent, "%s\n", __func__); ret = reg_write(icd, MT9M001_RESET, 1); if (ret >= 0) diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index eafb0c7736e..b72e5660bc1 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c @@ -5833,7 +5833,7 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) goto error; memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev)); - ov->vdev->dev = &intf->dev; + ov->vdev->parent = &intf->dev; video_set_drvdata(ov->vdev, ov); for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) { diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 423fa7c2d0c..b4de82115e5 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -1767,7 +1767,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id return -ENOMEM; } memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); - pdev->vdev->dev = &(udev->dev); + pdev->vdev->parent = &(udev->dev); strcpy(pdev->vdev->name, name); pdev->vdev->owner = THIS_MODULE; video_set_drvdata(pdev->vdev, pdev); diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c index 04eb2c3fabd..5f8cd3de98e 100644 --- a/drivers/media/video/s2255drv.c +++ b/drivers/media/video/s2255drv.c @@ -1706,7 +1706,7 @@ static int s2255_probe_v4l(struct s2255_dev *dev) /* register 4 video devices */ dev->vdev[i] = video_device_alloc(); memcpy(dev->vdev[i], &template, sizeof(struct video_device)); - dev->vdev[i]->dev = &dev->interface->dev; + dev->vdev[i]->parent = &dev->interface->dev; if (video_nr == -1) ret = video_register_device(dev->vdev[i], VFL_TYPE_GRABBER, diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index cfee84ee7a8..f3e7a598e4b 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -798,7 +798,7 @@ static struct video_device *vdev_init(struct saa7134_dev *dev, return NULL; *vfd = *template; vfd->minor = -1; - vfd->dev = &dev->pci->dev; + vfd->parent = &dev->pci->dev; vfd->release = video_device_release; vfd->debug = video_debug; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 2a5ab957542..3854cc29752 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -465,7 +465,7 @@ static int empress_init(struct saa7134_dev *dev) if (NULL == dev->empress_dev) return -ENOMEM; *(dev->empress_dev) = saa7134_empress_template; - dev->empress_dev->dev = &dev->pci->dev; + dev->empress_dev->parent = &dev->pci->dev; dev->empress_dev->release = video_device_release; snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name), "%s empress (%s)", dev->name, diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index e39b98f1eca..58c8c39b959 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -193,7 +193,7 @@ static int soc_camera_open(struct inode *inode, struct file *file) mutex_lock(&video_lock); vdev = video_devdata(file); - icd = container_of(vdev->dev, struct soc_camera_device, dev); + icd = container_of(vdev->parent, struct soc_camera_device, dev); ici = to_soc_camera_host(icd->dev.parent); if (!try_module_get(icd->ops->owner)) { @@ -258,7 +258,7 @@ static int soc_camera_close(struct inode *inode, struct file *file) vfree(icf); - dev_dbg(vdev->dev, "camera device close\n"); + dev_dbg(vdev->parent, "camera device close\n"); return 0; } @@ -271,7 +271,7 @@ static ssize_t soc_camera_read(struct file *file, char __user *buf, struct video_device *vdev = icd->vdev; int err = -EINVAL; - dev_err(vdev->dev, "camera device read not implemented\n"); + dev_err(vdev->parent, "camera device read not implemented\n"); return err; } @@ -877,7 +877,7 @@ int soc_camera_video_start(struct soc_camera_device *icd) strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); /* Maybe better &ici->dev */ - vdev->dev = &icd->dev; + vdev->parent = &icd->dev; vdev->type = VID_TYPE_CAPTURE; vdev->current_norm = V4L2_STD_UNKNOWN; vdev->fops = &soc_camera_fops; @@ -915,7 +915,7 @@ int soc_camera_video_start(struct soc_camera_device *icd) err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor); if (err < 0) { - dev_err(vdev->dev, "video_register_device failed\n"); + dev_err(vdev->parent, "video_register_device failed\n"); goto evidregd; } icd->vdev = vdev; diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index f308c38d744..5998a548319 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -1369,7 +1369,7 @@ static int stk_register_video_device(struct stk_camera *dev) dev->vdev = stk_v4l_data; dev->vdev.debug = debug; - dev->vdev.dev = &dev->interface->dev; + dev->vdev.parent = &dev->interface->dev; dev->vdev.priv = dev; err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); if (err) diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index d7f130bedb5..27e2f4aac13 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -1454,7 +1454,7 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id goto error; } memcpy(stv680->vdev, &stv680_template, sizeof(stv680_template)); - stv680->vdev->dev = &intf->dev; + stv680->vdev->parent = &intf->dev; video_set_drvdata(stv680->vdev, stv680); memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name)); diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c index 4128ee20b64..7e6ab2910c1 100644 --- a/drivers/media/video/usbvideo/usbvideo.c +++ b/drivers/media/video/usbvideo/usbvideo.c @@ -1040,7 +1040,7 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd) err("%s: uvd->dev == NULL", __func__); return -EINVAL; } - uvd->vdev.dev = &uvd->dev->dev; + uvd->vdev.parent = &uvd->dev->dev; if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { err("%s: video_register_device failed", __func__); return -EPIPE; diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index cd6c41d6789..899906d954a 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -1506,7 +1506,7 @@ static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision, } *vdev = *vdev_template; // vdev->minor = -1; - vdev->dev = &usb_dev->dev; + vdev->parent = &usb_dev->dev; snprintf(vdev->name, sizeof(vdev->name), "%s", name); video_set_drvdata(vdev, usbvision); return vdev; diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index f2b2983fe06..79d6821c474 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -1458,7 +1458,7 @@ static int uvc_register_video(struct uvc_device *dev) * unregistered before the reference is released, so we don't need to * get another one. */ - vdev->dev = &dev->intf->dev; + vdev->parent = &dev->intf->dev; vdev->type = 0; vdev->type2 = 0; vdev->minor = -1; diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 2dd82b16bc3..9cc2cf1a1c9 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -201,7 +201,7 @@ static int get_index(struct video_device *vdev, int num) for (i = 0; i < VIDEO_NUM_DEVICES; i++) { if (video_device[i] != NULL && video_device[i] != vdev && - video_device[i]->dev == vdev->dev) { + video_device[i]->parent == vdev->parent) { used |= 1 << video_device[i]->index; } } @@ -323,8 +323,8 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev)); vfd->class_dev.class = &video_class; vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); - if (vfd->dev) - vfd->class_dev.parent = vfd->dev; + if (vfd->parent) + vfd->class_dev.parent = vfd->parent; sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base); ret = device_register(&vfd->class_dev); if (ret < 0) { diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 840522442d0..3f5a59dc5f8 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -3555,7 +3555,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; video_set_drvdata(cam->v4ldev, cam); - cam->v4ldev->dev = &cam->dev; + cam->v4ldev->parent = &cam->dev; err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, video_nr[dev_nr]); -- cgit v1.2.3 From 22a04f106346c3af019135f2de3cabf9ac41c3ba Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 20 Jul 2008 06:35:02 -0300 Subject: V4L/DVB (8429): videodev: renamed 'class_dev' to 'dev' The class_dev field is a normal device, not a class device. This is very confusing and now that the old 'dev' field has been renamed to 'parent' we can rename 'class_dev' to just 'dev'. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 4 +- drivers/media/video/et61x251/et61x251_core.c | 2 +- drivers/media/video/sn9c102/sn9c102_core.c | 60 +++++++++------------ drivers/media/video/usbvision/usbvision-video.c | 72 ++++++++++--------------- drivers/media/video/v4l2-dev.c | 23 ++++---- 5 files changed, 65 insertions(+), 96 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 3dda84d115d..fff2fffcad6 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -163,7 +163,7 @@ MODULE_LICENSE("GPL"); static ssize_t show_card(struct device *cd, struct device_attribute *attr, char *buf) { - struct video_device *vfd = container_of(cd, struct video_device, class_dev); + struct video_device *vfd = container_of(cd, struct video_device, dev); struct bttv *btv = dev_get_drvdata(vfd->parent); return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET); } @@ -4244,7 +4244,7 @@ static int __devinit bttv_register_video(struct bttv *btv) goto err; printk(KERN_INFO "bttv%d: registered device video%d\n", btv->c.nr,btv->video_dev->minor & 0x1f); - if (device_create_file(&btv->video_dev->class_dev, + if (device_create_file(&btv->video_dev->dev, &dev_attr_card)<0) { printk(KERN_ERR "bttv%d: device_create_file 'card' " "failed\n", btv->c.nr); diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 15d037ae25c..3eea1333a52 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -985,7 +985,7 @@ static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, static int et61x251_create_sysfs(struct et61x251_device* cam) { - struct device *classdev = &(cam->v4ldev->class_dev); + struct device *classdev = &(cam->v4ldev->dev); int err = 0; if ((err = device_create_file(classdev, &dev_attr_reg))) diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 7f9c7bcf3c8..475b7819115 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -1038,8 +1038,7 @@ static ssize_t sn9c102_show_reg(struct device* cd, if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; - cam = video_get_drvdata(container_of(cd, struct video_device, - class_dev)); + cam = video_get_drvdata(container_of(cd, struct video_device, dev)); if (!cam) { mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; @@ -1064,8 +1063,7 @@ sn9c102_store_reg(struct device* cd, struct device_attribute *attr, if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; - cam = video_get_drvdata(container_of(cd, struct video_device, - class_dev)); + cam = video_get_drvdata(container_of(cd, struct video_device, dev)); if (!cam) { mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; @@ -1098,8 +1096,7 @@ static ssize_t sn9c102_show_val(struct device* cd, if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; - cam = video_get_drvdata(container_of(cd, struct video_device, - class_dev)); + cam = video_get_drvdata(container_of(cd, struct video_device, dev)); if (!cam) { mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; @@ -1132,8 +1129,7 @@ sn9c102_store_val(struct device* cd, struct device_attribute *attr, if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; - cam = video_get_drvdata(container_of(cd, struct video_device, - class_dev)); + cam = video_get_drvdata(container_of(cd, struct video_device, dev)); if (!cam) { mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; @@ -1170,8 +1166,7 @@ static ssize_t sn9c102_show_i2c_reg(struct device* cd, if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; - cam = video_get_drvdata(container_of(cd, struct video_device, - class_dev)); + cam = video_get_drvdata(container_of(cd, struct video_device, dev)); if (!cam) { mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; @@ -1198,8 +1193,7 @@ sn9c102_store_i2c_reg(struct device* cd, struct device_attribute *attr, if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; - cam = video_get_drvdata(container_of(cd, struct video_device, - class_dev)); + cam = video_get_drvdata(container_of(cd, struct video_device, dev)); if (!cam) { mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; @@ -1232,8 +1226,7 @@ static ssize_t sn9c102_show_i2c_val(struct device* cd, if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; - cam = video_get_drvdata(container_of(cd, struct video_device, - class_dev)); + cam = video_get_drvdata(container_of(cd, struct video_device, dev)); if (!cam) { mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; @@ -1271,8 +1264,7 @@ sn9c102_store_i2c_val(struct device* cd, struct device_attribute *attr, if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; - cam = video_get_drvdata(container_of(cd, struct video_device, - class_dev)); + cam = video_get_drvdata(container_of(cd, struct video_device, dev)); if (!cam) { mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; @@ -1318,8 +1310,7 @@ sn9c102_store_green(struct device* cd, struct device_attribute *attr, if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; - cam = video_get_drvdata(container_of(cd, struct video_device, - class_dev)); + cam = video_get_drvdata(container_of(cd, struct video_device, dev)); if (!cam) { mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; @@ -1400,8 +1391,7 @@ static ssize_t sn9c102_show_frame_header(struct device* cd, struct sn9c102_device* cam; ssize_t count; - cam = video_get_drvdata(container_of(cd, struct video_device, - class_dev)); + cam = video_get_drvdata(container_of(cd, struct video_device, dev)); if (!cam) return -ENODEV; @@ -1428,49 +1418,49 @@ static DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL); static int sn9c102_create_sysfs(struct sn9c102_device* cam) { - struct device *classdev = &(cam->v4ldev->class_dev); + struct device *dev = &(cam->v4ldev->dev); int err = 0; - if ((err = device_create_file(classdev, &dev_attr_reg))) + if ((err = device_create_file(dev, &dev_attr_reg))) goto err_out; - if ((err = device_create_file(classdev, &dev_attr_val))) + if ((err = device_create_file(dev, &dev_attr_val))) goto err_reg; - if ((err = device_create_file(classdev, &dev_attr_frame_header))) + if ((err = device_create_file(dev, &dev_attr_frame_header))) goto err_val; if (cam->sensor.sysfs_ops) { - if ((err = device_create_file(classdev, &dev_attr_i2c_reg))) + if ((err = device_create_file(dev, &dev_attr_i2c_reg))) goto err_frame_header; - if ((err = device_create_file(classdev, &dev_attr_i2c_val))) + if ((err = device_create_file(dev, &dev_attr_i2c_val))) goto err_i2c_reg; } if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { - if ((err = device_create_file(classdev, &dev_attr_green))) + if ((err = device_create_file(dev, &dev_attr_green))) goto err_i2c_val; } else { - if ((err = device_create_file(classdev, &dev_attr_blue))) + if ((err = device_create_file(dev, &dev_attr_blue))) goto err_i2c_val; - if ((err = device_create_file(classdev, &dev_attr_red))) + if ((err = device_create_file(dev, &dev_attr_red))) goto err_blue; } return 0; err_blue: - device_remove_file(classdev, &dev_attr_blue); + device_remove_file(dev, &dev_attr_blue); err_i2c_val: if (cam->sensor.sysfs_ops) - device_remove_file(classdev, &dev_attr_i2c_val); + device_remove_file(dev, &dev_attr_i2c_val); err_i2c_reg: if (cam->sensor.sysfs_ops) - device_remove_file(classdev, &dev_attr_i2c_reg); + device_remove_file(dev, &dev_attr_i2c_reg); err_frame_header: - device_remove_file(classdev, &dev_attr_frame_header); + device_remove_file(dev, &dev_attr_frame_header); err_val: - device_remove_file(classdev, &dev_attr_val); + device_remove_file(dev, &dev_attr_val); err_reg: - device_remove_file(classdev, &dev_attr_reg); + device_remove_file(dev, &dev_attr_reg); err_out: return err; } diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 899906d954a..2ddfaa34e6b 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -184,7 +184,7 @@ MODULE_ALIAS(DRIVER_ALIAS); static inline struct usb_usbvision *cd_to_usbvision(struct device *cd) { struct video_device *vdev = - container_of(cd, struct video_device, class_dev); + container_of(cd, struct video_device, dev); return video_get_drvdata(vdev); } @@ -199,7 +199,7 @@ static ssize_t show_model(struct device *cd, struct device_attribute *attr, char *buf) { struct video_device *vdev = - container_of(cd, struct video_device, class_dev); + container_of(cd, struct video_device, dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString); @@ -210,7 +210,7 @@ static ssize_t show_hue(struct device *cd, struct device_attribute *attr, char *buf) { struct video_device *vdev = - container_of(cd, struct video_device, class_dev); + container_of(cd, struct video_device, dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); struct v4l2_control ctrl; ctrl.id = V4L2_CID_HUE; @@ -225,7 +225,7 @@ static ssize_t show_contrast(struct device *cd, struct device_attribute *attr, char *buf) { struct video_device *vdev = - container_of(cd, struct video_device, class_dev); + container_of(cd, struct video_device, dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); struct v4l2_control ctrl; ctrl.id = V4L2_CID_CONTRAST; @@ -240,7 +240,7 @@ static ssize_t show_brightness(struct device *cd, struct device_attribute *attr, char *buf) { struct video_device *vdev = - container_of(cd, struct video_device, class_dev); + container_of(cd, struct video_device, dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); struct v4l2_control ctrl; ctrl.id = V4L2_CID_BRIGHTNESS; @@ -255,7 +255,7 @@ static ssize_t show_saturation(struct device *cd, struct device_attribute *attr, char *buf) { struct video_device *vdev = - container_of(cd, struct video_device, class_dev); + container_of(cd, struct video_device, dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); struct v4l2_control ctrl; ctrl.id = V4L2_CID_SATURATION; @@ -270,7 +270,7 @@ static ssize_t show_streaming(struct device *cd, struct device_attribute *attr, char *buf) { struct video_device *vdev = - container_of(cd, struct video_device, class_dev); + container_of(cd, struct video_device, dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0)); @@ -281,7 +281,7 @@ static ssize_t show_compression(struct device *cd, struct device_attribute *attr, char *buf) { struct video_device *vdev = - container_of(cd, struct video_device, class_dev); + container_of(cd, struct video_device, dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS)); @@ -292,7 +292,7 @@ static ssize_t show_device_bridge(struct device *cd, struct device_attribute *attr, char *buf) { struct video_device *vdev = - container_of(cd, struct video_device, class_dev); + container_of(cd, struct video_device, dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%d\n", usbvision->bridgeType); } @@ -304,40 +304,31 @@ static void usbvision_create_sysfs(struct video_device *vdev) if (!vdev) return; do { - res = device_create_file(&vdev->class_dev, - &dev_attr_version); + res = device_create_file(&vdev->dev, &dev_attr_version); if (res<0) break; - res = device_create_file(&vdev->class_dev, - &dev_attr_model); + res = device_create_file(&vdev->dev, &dev_attr_model); if (res<0) break; - res = device_create_file(&vdev->class_dev, - &dev_attr_hue); + res = device_create_file(&vdev->dev, &dev_attr_hue); if (res<0) break; - res = device_create_file(&vdev->class_dev, - &dev_attr_contrast); + res = device_create_file(&vdev->dev, &dev_attr_contrast); if (res<0) break; - res = device_create_file(&vdev->class_dev, - &dev_attr_brightness); + res = device_create_file(&vdev->dev, &dev_attr_brightness); if (res<0) break; - res = device_create_file(&vdev->class_dev, - &dev_attr_saturation); + res = device_create_file(&vdev->dev, &dev_attr_saturation); if (res<0) break; - res = device_create_file(&vdev->class_dev, - &dev_attr_streaming); + res = device_create_file(&vdev->dev, &dev_attr_streaming); if (res<0) break; - res = device_create_file(&vdev->class_dev, - &dev_attr_compression); + res = device_create_file(&vdev->dev, &dev_attr_compression); if (res<0) break; - res = device_create_file(&vdev->class_dev, - &dev_attr_bridge); + res = device_create_file(&vdev->dev, &dev_attr_bridge); if (res>=0) return; } while (0); @@ -348,24 +339,15 @@ static void usbvision_create_sysfs(struct video_device *vdev) static void usbvision_remove_sysfs(struct video_device *vdev) { if (vdev) { - device_remove_file(&vdev->class_dev, - &dev_attr_version); - device_remove_file(&vdev->class_dev, - &dev_attr_model); - device_remove_file(&vdev->class_dev, - &dev_attr_hue); - device_remove_file(&vdev->class_dev, - &dev_attr_contrast); - device_remove_file(&vdev->class_dev, - &dev_attr_brightness); - device_remove_file(&vdev->class_dev, - &dev_attr_saturation); - device_remove_file(&vdev->class_dev, - &dev_attr_streaming); - device_remove_file(&vdev->class_dev, - &dev_attr_compression); - device_remove_file(&vdev->class_dev, - &dev_attr_bridge); + device_remove_file(&vdev->dev, &dev_attr_version); + device_remove_file(&vdev->dev, &dev_attr_model); + device_remove_file(&vdev->dev, &dev_attr_hue); + device_remove_file(&vdev->dev, &dev_attr_contrast); + device_remove_file(&vdev->dev, &dev_attr_brightness); + device_remove_file(&vdev->dev, &dev_attr_saturation); + device_remove_file(&vdev->dev, &dev_attr_streaming); + device_remove_file(&vdev->dev, &dev_attr_compression); + device_remove_file(&vdev->dev, &dev_attr_bridge); } } diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 9cc2cf1a1c9..88eeee1d8ba 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -41,16 +41,14 @@ static ssize_t show_index(struct device *cd, struct device_attribute *attr, char *buf) { - struct video_device *vfd = container_of(cd, struct video_device, - class_dev); + struct video_device *vfd = container_of(cd, struct video_device, dev); return sprintf(buf, "%i\n", vfd->index); } static ssize_t show_name(struct device *cd, struct device_attribute *attr, char *buf) { - struct video_device *vfd = container_of(cd, struct video_device, - class_dev); + struct video_device *vfd = container_of(cd, struct video_device, dev); return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name); } @@ -77,8 +75,7 @@ EXPORT_SYMBOL(video_device_release); static void video_release(struct device *cd) { - struct video_device *vfd = container_of(cd, struct video_device, - class_dev); + struct video_device *vfd = container_of(cd, struct video_device, dev); #if 1 /* needed until all drivers are fixed */ @@ -320,13 +317,13 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, mutex_init(&vfd->lock); /* sysfs class */ - memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev)); - vfd->class_dev.class = &video_class; - vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); + memset(&vfd->dev, 0x00, sizeof(vfd->dev)); + vfd->dev.class = &video_class; + vfd->dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); if (vfd->parent) - vfd->class_dev.parent = vfd->parent; - sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base); - ret = device_register(&vfd->class_dev); + vfd->dev.parent = vfd->parent; + sprintf(vfd->dev.bus_id, "%s%d", name_base, i - base); + ret = device_register(&vfd->dev); if (ret < 0) { printk(KERN_ERR "%s: device_register failed\n", __func__); goto fail_minor; @@ -365,7 +362,7 @@ void video_unregister_device(struct video_device *vfd) panic("videodev: bad unregister"); video_device[vfd->minor] = NULL; - device_unregister(&vfd->class_dev); + device_unregister(&vfd->dev); mutex_unlock(&videodev_lock); } EXPORT_SYMBOL(video_unregister_device); -- cgit v1.2.3 From e81cf44428b9540d489a12880663488708bbb9c1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 20 Jul 2008 10:49:39 -0300 Subject: V4L/DVB (8433): Fix macro name at z0194a.h As reported by Hans Verkuil: In file included from /home/v4l/master/v4l/dw2102.c:14: /home/v4l/master/v4l/z0194a.h:93: error: 'STV0229_LOCKOUTPUT_1' undeclared here (not in a function) This is due to some typos that were fixed on stv0299. This patch renames it in accord with that fix. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/z0194a.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/z0194a.h b/drivers/media/dvb/frontends/z0194a.h index b5ca9e75421..d2876d2e176 100644 --- a/drivers/media/dvb/frontends/z0194a.h +++ b/drivers/media/dvb/frontends/z0194a.h @@ -88,7 +88,7 @@ static struct stv0299_config sharp_z0194a_config = { .mclk = 88000000UL, .invert = 1, .skip_reinit = 0, - .lock_output = STV0229_LOCKOUTPUT_1, + .lock_output = STV0299_LOCKOUTPUT_1, .volt13_op0_op1 = STV0299_VOLT13_OP1, .min_delay_ms = 100, .set_symbol_rate = sharp_z0194a__set_symbol_rate, -- cgit v1.2.3 From 2339788376e2d69a9154130e4dacd5b21ce63094 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 23 Jul 2008 20:05:34 -0700 Subject: md: fix merge error The original STRIPE_OP_IO removal patch had the following hunk: - for (i = conf->raid_disks; i--; ) { + for (i = conf->raid_disks; i--; ) set_bit(R5_Wantwrite, &sh->dev[i].flags); - if (!test_and_set_bit(STRIPE_OP_IO, &sh->ops.pending)) - sh->ops.count++; - } However it appears the hunk became broken after merging: - for (i = conf->raid_disks; i--; ) { + for (i = conf->raid_disks; i--; ) set_bit(R5_Wantwrite, &sh->dev[i].flags); set_bit(R5_LOCKED, &dev->flags); s.locked++; - if (!test_and_set_bit(STRIPE_OP_IO, &sh->ops.pending)) - sh->ops.count++; - } Signed-off-by: Dan Williams --- drivers/md/raid5.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 8a6f101d322..46132fca346 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2717,10 +2717,11 @@ static void handle_stripe5(struct stripe_head *sh) if (sh->reconstruct_state == reconstruct_state_result) { sh->reconstruct_state = reconstruct_state_idle; clear_bit(STRIPE_EXPANDING, &sh->state); - for (i = conf->raid_disks; i--; ) + for (i = conf->raid_disks; i--; ) { set_bit(R5_Wantwrite, &sh->dev[i].flags); - set_bit(R5_LOCKED, &dev->flags); + set_bit(R5_LOCKED, &sh->dev[i].flags); s.locked++; + } } if (s.expanded && test_bit(STRIPE_EXPANDING, &sh->state) && -- cgit v1.2.3 From d8e64406a037a64444175730294e449c9e21f5ec Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 23 Jul 2008 13:09:48 -0700 Subject: md: delay notification of 'active_idle' to the recovery thread sysfs_notify might sleep, so do not call it from md_safemode_timeout. Signed-off-by: Dan Williams --- drivers/md/md.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index c2ff77ccec5..0f1b8309642 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3483,7 +3483,7 @@ static void md_safemode_timeout(unsigned long data) if (!atomic_read(&mddev->writes_pending)) { mddev->safemode = 1; if (mddev->external) - sysfs_notify(&mddev->kobj, NULL, "array_state"); + set_bit(MD_NOTIFY_ARRAY_STATE, &mddev->flags); } md_wakeup_thread(mddev->thread); } @@ -6051,6 +6051,9 @@ void md_check_recovery(mddev_t *mddev) if (mddev->bitmap) bitmap_daemon_work(mddev->bitmap); + if (test_and_clear_bit(MD_NOTIFY_ARRAY_STATE, &mddev->flags)) + sysfs_notify(&mddev->kobj, NULL, "array_state"); + if (mddev->ro) return; -- cgit v1.2.3 From 35ea11ff84719b1bfab2909903a9640a86552fd1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 20 Jul 2008 08:12:02 -0300 Subject: V4L/DVB (8430): videodev: move some functions from v4l2-dev.h to v4l2-common.h or v4l2-ioctl.h The functions in a header should not belong to another module. The prio functions belong to v4l2-common.c, so move them to v4l2-common.h. The ioctl functions belong to v4l2-ioctl.c, so create a new v4l2-ioctl.h header and move those functions to it. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/dsbr100.c | 1 + drivers/media/radio/miropcm20-radio.c | 1 + drivers/media/radio/radio-aimslab.c | 1 + drivers/media/radio/radio-aztech.c | 1 + drivers/media/radio/radio-cadet.c | 1 + drivers/media/radio/radio-gemtek-pci.c | 1 + drivers/media/radio/radio-gemtek.c | 1 + drivers/media/radio/radio-maestro.c | 1 + drivers/media/radio/radio-maxiradio.c | 1 + drivers/media/radio/radio-rtrack2.c | 1 + drivers/media/radio/radio-sf16fmi.c | 1 + drivers/media/radio/radio-sf16fmr2.c | 1 + drivers/media/radio/radio-si470x.c | 1 + drivers/media/radio/radio-terratec.c | 1 + drivers/media/radio/radio-trust.c | 1 + drivers/media/radio/radio-typhoon.c | 1 + drivers/media/radio/radio-zoltrix.c | 1 + drivers/media/video/bt8xx/bttv-driver.c | 1 + drivers/media/video/bt8xx/bttv-risc.c | 1 + drivers/media/video/bt8xx/bttv-vbi.c | 1 + drivers/media/video/bw-qcam.c | 1 + drivers/media/video/c-qcam.c | 1 + drivers/media/video/cafe_ccic.c | 1 + drivers/media/video/cpia.h | 1 + drivers/media/video/cpia2/cpia2_v4l.c | 1 + drivers/media/video/cx18/cx18-driver.h | 1 + drivers/media/video/cx23885/cx23885-417.c | 1 + drivers/media/video/cx23885/cx23885-video.c | 1 + drivers/media/video/cx88/cx88-blackbird.c | 1 + drivers/media/video/cx88/cx88-core.c | 1 + drivers/media/video/cx88/cx88-video.c | 1 + drivers/media/video/em28xx/em28xx-video.c | 1 + drivers/media/video/et61x251/et61x251_core.c | 1 + drivers/media/video/gspca/gspca.c | 1 + drivers/media/video/ivtv/ivtv-driver.h | 1 + drivers/media/video/meye.c | 1 + drivers/media/video/msp3400-driver.c | 1 + drivers/media/video/ov511.h | 1 + drivers/media/video/pms.c | 1 + drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 1 + drivers/media/video/pwc/pwc.h | 1 + drivers/media/video/s2255drv.c | 1 + drivers/media/video/saa5246a.c | 1 + drivers/media/video/saa5249.c | 1 + drivers/media/video/saa7134/saa7134.h | 1 + drivers/media/video/se401.h | 1 + drivers/media/video/sn9c102/sn9c102.h | 1 + drivers/media/video/soc_camera.c | 1 + drivers/media/video/stk-webcam.c | 1 + drivers/media/video/stv680.c | 1 + drivers/media/video/tda7432.c | 1 + drivers/media/video/tuner-core.c | 1 + drivers/media/video/usbvideo/usbvideo.h | 1 + drivers/media/video/usbvision/usbvision-video.c | 1 + drivers/media/video/uvc/uvc_v4l2.c | 1 + drivers/media/video/v4l1-compat.c | 1 + drivers/media/video/v4l2-ioctl.c | 1865 +++++++++++++++++++++++ drivers/media/video/vivi.c | 1 + drivers/media/video/w9966.c | 1 + drivers/media/video/zc0301/zc0301.h | 1 + drivers/media/video/zoran_driver.c | 1 + drivers/media/video/zr364xx.c | 1 + 62 files changed, 1926 insertions(+) create mode 100644 drivers/media/video/v4l2-ioctl.c (limited to 'drivers') diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index 4e3f83e4e48..97c6853ad1d 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -85,6 +85,7 @@ #include #include #include +#include #include /* diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c index 09fe6f1cdf1..4a332fe8b64 100644 --- a/drivers/media/radio/miropcm20-radio.c +++ b/drivers/media/radio/miropcm20-radio.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "oss/aci.h" #include "miropcm20-rds-core.h" diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 1ec18ed1a73..ec8d64704dd 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -36,6 +36,7 @@ #include /* copy to/from user */ #include /* kernel radio structs */ #include +#include #include /* for KERNEL_VERSION MACRO */ #define RADIO_VERSION KERNEL_VERSION(0,0,2) diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c index 46cdb549eac..639164a974a 100644 --- a/drivers/media/radio/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c @@ -33,6 +33,7 @@ #include /* copy to/from user */ #include /* kernel radio structs */ #include +#include #include /* for KERNEL_VERSION MACRO */ #define RADIO_VERSION KERNEL_VERSION(0,0,2) diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index b14db53ea45..484ea87d7fb 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -39,6 +39,7 @@ #include /* copy to/from user */ #include /* V4L2 API defs */ #include +#include #include #include diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c index de49be97148..2b834b95f3e 100644 --- a/drivers/media/radio/radio-gemtek-pci.c +++ b/drivers/media/radio/radio-gemtek-pci.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include /* for KERNEL_VERSION MACRO */ diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 81f6aeb1cd1..4740bacc2f8 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -23,6 +23,7 @@ #include /* outb, outb_p */ #include /* copy to/from user */ #include /* kernel radio structs */ +#include #include #include diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index bddd3c409aa..040a73fac69 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c @@ -27,6 +27,7 @@ #include #include #include +#include #include /* for KERNEL_VERSION MACRO */ #define RADIO_VERSION KERNEL_VERSION(0,0,6) diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index 0133ecf3e04..9e824a7d5cc 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -44,6 +44,7 @@ #include #include #include +#include #define DRIVER_VERSION "0.77" diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index 070802103dc..c3fb270f211 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c @@ -17,6 +17,7 @@ #include /* copy to/from user */ #include /* kernel radio structs */ #include +#include #include #include /* for KERNEL_VERSION MACRO */ diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 66e052fd390..bb8b1c9107b 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -24,6 +24,7 @@ #include /* udelay */ #include /* kernel radio structs */ #include +#include #include #include /* outb, outb_p */ #include /* copy to/from user */ diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index b0ccf7cb595..9fa025b704c 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -22,6 +22,7 @@ #include /* copy to/from user */ #include /* kernel radio structs */ #include +#include #include static struct mutex lock; diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index dc93a882b38..33361218017 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c @@ -133,6 +133,7 @@ #include #include #include +#include #include #include diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index acc32080e9b..a9914dbcf49 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -32,6 +32,7 @@ #include /* copy to/from user */ #include /* kernel radio structs */ #include +#include #include #include /* for KERNEL_VERSION MACRO */ diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index 4ebdfbadeb9..560c49481a2 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c @@ -23,6 +23,7 @@ #include #include #include +#include #include /* for KERNEL_VERSION MACRO */ #define RADIO_VERSION KERNEL_VERSION(0,0,2) diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c index 18f2abd7e25..023d6f3c751 100644 --- a/drivers/media/radio/radio-typhoon.c +++ b/drivers/media/radio/radio-typhoon.c @@ -40,6 +40,7 @@ #include /* copy to/from user */ #include /* kernel radio structs */ #include +#include #include /* for KERNEL_VERSION MACRO */ #define RADIO_VERSION KERNEL_VERSION(0,1,1) diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index 43773c56c62..cf0355bb6ef 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c @@ -37,6 +37,7 @@ #include /* copy to/from user */ #include /* kernel radio structs */ #include +#include #include /* for KERNEL_VERSION MACRO */ #define RADIO_VERSION KERNEL_VERSION(0,0,2) diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index fff2fffcad6..33c72055447 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -45,6 +45,7 @@ #include #include "bttvp.h" #include +#include #include #include diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c index 0af586876e7..649682aac1a 100644 --- a/drivers/media/video/bt8xx/bttv-risc.c +++ b/drivers/media/video/bt8xx/bttv-risc.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "bttvp.h" diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index 68f28e5fa04..6819e21a377 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "bttvp.h" diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index b364adaae78..e367862313e 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -74,6 +74,7 @@ OTHER DEALINGS IN THE SOFTWARE. #include #include #include +#include #include #include diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c index fe1e67bb1ca..8d690410c84 100644 --- a/drivers/media/video/c-qcam.c +++ b/drivers/media/video/c-qcam.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index ebcc8ad6271..302c57f151c 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/media/video/cpia.h b/drivers/media/video/cpia.h index 5096058bf57..8f0cfee4b8a 100644 --- a/drivers/media/video/cpia.h +++ b/drivers/media/video/cpia.h @@ -46,6 +46,7 @@ #include #include #include +#include #include #include diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 7ce2789fa97..8817c384146 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "cpia2.h" #include "cpia2dev.h" diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index 45e31b04730..4801bc7fb5b 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h @@ -46,6 +46,7 @@ #include #include #include +#include #include #include "cx18-mailbox.h" #include "cx18-av-core.h" diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index 1b252976eda..4d0dcb06c19 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "cx23885.h" diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 3b807ba874f..245712e45f6 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -33,6 +33,7 @@ #include "cx23885.h" #include +#include #ifdef CONFIG_VIDEO_V4L1_COMPAT /* Include V4L1 specific functions. Should be removed soon */ diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index bfdca584776..4d1a461f329 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "cx88.h" diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 2c0582e0559..d656fec5901 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -40,6 +40,7 @@ #include "cx88.h" #include +#include MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 0fed5cd2cce..d08c11eb8a7 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -39,6 +39,7 @@ #include "cx88.h" #include +#include #ifdef CONFIG_VIDEO_V4L1_COMPAT /* Include V4L1 specific functions. Should be removed soon */ diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 838e7ecfd86..67c62eaa5b6 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -38,6 +38,7 @@ #include "em28xx.h" #include +#include #include #include diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 3eea1333a52..8cd5f37425e 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index f5b77deab72..8170a6937b8 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "gspca.h" diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index a08bb3331cf..ab287b48fc2 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -60,6 +60,7 @@ #include #include #include +#include #include #include diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index 0045367a66f..a1fb9874fdc 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index 5691e019d19..780531b587a 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h index 1010e51189b..baded1262ca 100644 --- a/drivers/media/video/ov511.h +++ b/drivers/media/video/ov511.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c index 51b1461d8fb..260c1d3f969 100644 --- a/drivers/media/video/pms.c +++ b/drivers/media/video/pms.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 0d72dc470fe..bd6169fbdcc 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -30,6 +30,7 @@ #include #include #include +#include struct pvr2_v4l2_dev; struct pvr2_v4l2_fh; diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index 8e8e5b27e77..835db149a3b 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h @@ -35,6 +35,7 @@ #include #include #include +#include #include "pwc-uncompress.h" #include diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c index 5f8cd3de98e..eb81915935b 100644 --- a/drivers/media/video/s2255drv.c +++ b/drivers/media/video/s2255drv.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c index 03e772130b5..8d69632a665 100644 --- a/drivers/media/video/saa5246a.c +++ b/drivers/media/video/saa5246a.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include "saa5246a.h" diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c index fde99d9ee71..812cfe3fd3f 100644 --- a/drivers/media/video/saa5249.c +++ b/drivers/media/video/saa5249.c @@ -57,6 +57,7 @@ #include #include #include +#include #include diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 6927cbea862..ade4e19799e 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -34,6 +34,7 @@ #include #include +#include #include #include #include diff --git a/drivers/media/video/se401.h b/drivers/media/video/se401.h index 835ef872e80..2ce685db5d8 100644 --- a/drivers/media/video/se401.h +++ b/drivers/media/video/se401.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #define se401_DEBUG /* Turn on debug messages */ diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h index 0c8d87d8d18..cbfc44433b9 100644 --- a/drivers/media/video/sn9c102/sn9c102.h +++ b/drivers/media/video/sn9c102/sn9c102.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 58c8c39b959..b0174908847 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index 5998a548319..20028aeb842 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "stk-webcam.h" diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index 27e2f4aac13..da94d3fd8fa 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -66,6 +66,7 @@ #include #include #include +#include #include #include diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index ae75c187da7..2fda40c0f25 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -48,6 +48,7 @@ #include #include +#include #include #ifndef VIDEO_AUDIO_BALANCE diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 93d879dc510..d806a3556ee 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "mt20xx.h" #include "tda8290.h" diff --git a/drivers/media/video/usbvideo/usbvideo.h b/drivers/media/video/usbvideo/usbvideo.h index 051775d4c72..c66985beb8c 100644 --- a/drivers/media/video/usbvideo/usbvideo.h +++ b/drivers/media/video/usbvideo/usbvideo.h @@ -18,6 +18,7 @@ #include #include +#include #include #include diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 2ddfaa34e6b..56cd685d35e 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -65,6 +65,7 @@ #include #include +#include #include #include diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index b5a11eb8f9f..d7bd71be40a 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c @@ -23,6 +23,7 @@ #include #include +#include #include "uvcvideo.h" diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c index a0f6c60279e..79937d1031f 100644 --- a/drivers/media/video/v4l1-compat.c +++ b/drivers/media/video/v4l1-compat.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c new file mode 100644 index 00000000000..56a4fdee916 --- /dev/null +++ b/drivers/media/video/v4l2-ioctl.c @@ -0,0 +1,1865 @@ +/* + * Video capture interface for Linux version 2 + * + * A generic framework to process V4L2 ioctl commands. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Alan Cox, (version 1) + * Mauro Carvalho Chehab (version 2) + */ + +#include +#include +#include + +#define __OLD_VIDIOC_ /* To allow fixing old calls */ +#include + +#ifdef CONFIG_VIDEO_V4L1 +#include +#endif +#include +#include +#include + +#define dbgarg(cmd, fmt, arg...) \ + do { \ + if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \ + printk(KERN_DEBUG "%s: ", vfd->name); \ + v4l_printk_ioctl(cmd); \ + printk(" " fmt, ## arg); \ + } \ + } while (0) + +#define dbgarg2(fmt, arg...) \ + do { \ + if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ + printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);\ + } while (0) + +struct std_descr { + v4l2_std_id std; + const char *descr; +}; + +static const struct std_descr standards[] = { + { V4L2_STD_NTSC, "NTSC" }, + { V4L2_STD_NTSC_M, "NTSC-M" }, + { V4L2_STD_NTSC_M_JP, "NTSC-M-JP" }, + { V4L2_STD_NTSC_M_KR, "NTSC-M-KR" }, + { V4L2_STD_NTSC_443, "NTSC-443" }, + { V4L2_STD_PAL, "PAL" }, + { V4L2_STD_PAL_BG, "PAL-BG" }, + { V4L2_STD_PAL_B, "PAL-B" }, + { V4L2_STD_PAL_B1, "PAL-B1" }, + { V4L2_STD_PAL_G, "PAL-G" }, + { V4L2_STD_PAL_H, "PAL-H" }, + { V4L2_STD_PAL_I, "PAL-I" }, + { V4L2_STD_PAL_DK, "PAL-DK" }, + { V4L2_STD_PAL_D, "PAL-D" }, + { V4L2_STD_PAL_D1, "PAL-D1" }, + { V4L2_STD_PAL_K, "PAL-K" }, + { V4L2_STD_PAL_M, "PAL-M" }, + { V4L2_STD_PAL_N, "PAL-N" }, + { V4L2_STD_PAL_Nc, "PAL-Nc" }, + { V4L2_STD_PAL_60, "PAL-60" }, + { V4L2_STD_SECAM, "SECAM" }, + { V4L2_STD_SECAM_B, "SECAM-B" }, + { V4L2_STD_SECAM_G, "SECAM-G" }, + { V4L2_STD_SECAM_H, "SECAM-H" }, + { V4L2_STD_SECAM_DK, "SECAM-DK" }, + { V4L2_STD_SECAM_D, "SECAM-D" }, + { V4L2_STD_SECAM_K, "SECAM-K" }, + { V4L2_STD_SECAM_K1, "SECAM-K1" }, + { V4L2_STD_SECAM_L, "SECAM-L" }, + { V4L2_STD_SECAM_LC, "SECAM-Lc" }, + { 0, "Unknown" } +}; + +/* video4linux standard ID conversion to standard name + */ +const char *v4l2_norm_to_name(v4l2_std_id id) +{ + u32 myid = id; + int i; + + /* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle + 64 bit comparations. So, on that architecture, with some gcc + variants, compilation fails. Currently, the max value is 30bit wide. + */ + BUG_ON(myid != id); + + for (i = 0; standards[i].std; i++) + if (myid == standards[i].std) + break; + return standards[i].descr; +} +EXPORT_SYMBOL(v4l2_norm_to_name); + +/* Fill in the fields of a v4l2_standard structure according to the + 'id' and 'transmission' parameters. Returns negative on error. */ +int v4l2_video_std_construct(struct v4l2_standard *vs, + int id, const char *name) +{ + u32 index = vs->index; + + memset(vs, 0, sizeof(struct v4l2_standard)); + vs->index = index; + vs->id = id; + if (id & V4L2_STD_525_60) { + vs->frameperiod.numerator = 1001; + vs->frameperiod.denominator = 30000; + vs->framelines = 525; + } else { + vs->frameperiod.numerator = 1; + vs->frameperiod.denominator = 25; + vs->framelines = 625; + } + strlcpy(vs->name, name, sizeof(vs->name)); + return 0; +} +EXPORT_SYMBOL(v4l2_video_std_construct); + +/* ----------------------------------------------------------------- */ +/* some arrays for pretty-printing debug messages of enum types */ + +const char *v4l2_field_names[] = { + [V4L2_FIELD_ANY] = "any", + [V4L2_FIELD_NONE] = "none", + [V4L2_FIELD_TOP] = "top", + [V4L2_FIELD_BOTTOM] = "bottom", + [V4L2_FIELD_INTERLACED] = "interlaced", + [V4L2_FIELD_SEQ_TB] = "seq-tb", + [V4L2_FIELD_SEQ_BT] = "seq-bt", + [V4L2_FIELD_ALTERNATE] = "alternate", + [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb", + [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt", +}; +EXPORT_SYMBOL(v4l2_field_names); + +const char *v4l2_type_names[] = { + [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "vid-cap", + [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "vid-overlay", + [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "vid-out", + [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", + [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", + [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", + [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", + [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay", +}; +EXPORT_SYMBOL(v4l2_type_names); + +static const char *v4l2_memory_names[] = { + [V4L2_MEMORY_MMAP] = "mmap", + [V4L2_MEMORY_USERPTR] = "userptr", + [V4L2_MEMORY_OVERLAY] = "overlay", +}; + +#define prt_names(a, arr) ((((a) >= 0) && ((a) < ARRAY_SIZE(arr))) ? \ + arr[a] : "unknown") + +/* ------------------------------------------------------------------ */ +/* debug help functions */ + +#ifdef CONFIG_VIDEO_V4L1_COMPAT +static const char *v4l1_ioctls[] = { + [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP", + [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN", + [_IOC_NR(VIDIOCSCHAN)] = "VIDIOCSCHAN", + [_IOC_NR(VIDIOCGTUNER)] = "VIDIOCGTUNER", + [_IOC_NR(VIDIOCSTUNER)] = "VIDIOCSTUNER", + [_IOC_NR(VIDIOCGPICT)] = "VIDIOCGPICT", + [_IOC_NR(VIDIOCSPICT)] = "VIDIOCSPICT", + [_IOC_NR(VIDIOCCAPTURE)] = "VIDIOCCAPTURE", + [_IOC_NR(VIDIOCGWIN)] = "VIDIOCGWIN", + [_IOC_NR(VIDIOCSWIN)] = "VIDIOCSWIN", + [_IOC_NR(VIDIOCGFBUF)] = "VIDIOCGFBUF", + [_IOC_NR(VIDIOCSFBUF)] = "VIDIOCSFBUF", + [_IOC_NR(VIDIOCKEY)] = "VIDIOCKEY", + [_IOC_NR(VIDIOCGFREQ)] = "VIDIOCGFREQ", + [_IOC_NR(VIDIOCSFREQ)] = "VIDIOCSFREQ", + [_IOC_NR(VIDIOCGAUDIO)] = "VIDIOCGAUDIO", + [_IOC_NR(VIDIOCSAUDIO)] = "VIDIOCSAUDIO", + [_IOC_NR(VIDIOCSYNC)] = "VIDIOCSYNC", + [_IOC_NR(VIDIOCMCAPTURE)] = "VIDIOCMCAPTURE", + [_IOC_NR(VIDIOCGMBUF)] = "VIDIOCGMBUF", + [_IOC_NR(VIDIOCGUNIT)] = "VIDIOCGUNIT", + [_IOC_NR(VIDIOCGCAPTURE)] = "VIDIOCGCAPTURE", + [_IOC_NR(VIDIOCSCAPTURE)] = "VIDIOCSCAPTURE", + [_IOC_NR(VIDIOCSPLAYMODE)] = "VIDIOCSPLAYMODE", + [_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE", + [_IOC_NR(VIDIOCGPLAYINFO)] = "VIDIOCGPLAYINFO", + [_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE", + [_IOC_NR(VIDIOCGVBIFMT)] = "VIDIOCGVBIFMT", + [_IOC_NR(VIDIOCSVBIFMT)] = "VIDIOCSVBIFMT" +}; +#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls) +#endif + +static const char *v4l2_ioctls[] = { + [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP", + [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED", + [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT", + [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT", + [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT", + [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS", + [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF", + [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF", + [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF", + [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY", + [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF", + [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF", + [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON", + [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF", + [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM", + [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM", + [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD", + [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD", + [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD", + [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT", + [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL", + [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL", + [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER", + [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER", + [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO", + [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO", + [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL", + [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU", + [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT", + [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT", + [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT", + [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT", + [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT", + [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT", + [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT", + [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR", + [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR", + [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY", + [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY", + [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP", + [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP", + [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP", + [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP", + [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP", + [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD", + [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT", + [_IOC_NR(VIDIOC_ENUMAUDIO)] = "VIDIOC_ENUMAUDIO", + [_IOC_NR(VIDIOC_ENUMAUDOUT)] = "VIDIOC_ENUMAUDOUT", + [_IOC_NR(VIDIOC_G_PRIORITY)] = "VIDIOC_G_PRIORITY", + [_IOC_NR(VIDIOC_S_PRIORITY)] = "VIDIOC_S_PRIORITY", + [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP", + [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS", + [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS", + [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS", + [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS", +#if 1 + [_IOC_NR(VIDIOC_ENUM_FRAMESIZES)] = "VIDIOC_ENUM_FRAMESIZES", + [_IOC_NR(VIDIOC_ENUM_FRAMEINTERVALS)] = "VIDIOC_ENUM_FRAMEINTERVALS", + [_IOC_NR(VIDIOC_G_ENC_INDEX)] = "VIDIOC_G_ENC_INDEX", + [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD", + [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD", + + [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", + [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", + + [_IOC_NR(VIDIOC_G_CHIP_IDENT)] = "VIDIOC_G_CHIP_IDENT", + [_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK", +#endif +}; +#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) + +static const char *v4l2_int_ioctls[] = { +#ifdef CONFIG_VIDEO_V4L1_COMPAT + [_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES", + [_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS", + [_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM", + [_IOC_NR(DECODER_SET_INPUT)] = "DECODER_SET_INPUT", + [_IOC_NR(DECODER_SET_OUTPUT)] = "DECODER_SET_OUTPUT", + [_IOC_NR(DECODER_ENABLE_OUTPUT)] = "DECODER_ENABLE_OUTPUT", + [_IOC_NR(DECODER_SET_PICTURE)] = "DECODER_SET_PICTURE", + [_IOC_NR(DECODER_SET_GPIO)] = "DECODER_SET_GPIO", + [_IOC_NR(DECODER_INIT)] = "DECODER_INIT", + [_IOC_NR(DECODER_SET_VBI_BYPASS)] = "DECODER_SET_VBI_BYPASS", + [_IOC_NR(DECODER_DUMP)] = "DECODER_DUMP", +#endif + [_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO", + + [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR", + [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY", + [_IOC_NR(TUNER_SET_CONFIG)] = "TUNER_SET_CONFIG", + + [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE", + [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET", + [_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ", + [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE", + [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA", + [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA", + [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ", + [_IOC_NR(VIDIOC_INT_S_STANDBY)] = "VIDIOC_INT_S_STANDBY", + [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING", + [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING", + [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING", + [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING", + [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ", + [_IOC_NR(VIDIOC_INT_INIT)] = "VIDIOC_INT_INIT", + [_IOC_NR(VIDIOC_INT_G_STD_OUTPUT)] = "VIDIOC_INT_G_STD_OUTPUT", + [_IOC_NR(VIDIOC_INT_S_STD_OUTPUT)] = "VIDIOC_INT_S_STD_OUTPUT", +}; +#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls) + +/* Common ioctl debug function. This function can be used by + external ioctl messages as well as internal V4L ioctl */ +void v4l_printk_ioctl(unsigned int cmd) +{ + char *dir, *type; + + switch (_IOC_TYPE(cmd)) { + case 'd': + if (_IOC_NR(cmd) >= V4L2_INT_IOCTLS) { + type = "v4l2_int"; + break; + } + printk("%s", v4l2_int_ioctls[_IOC_NR(cmd)]); + return; +#ifdef CONFIG_VIDEO_V4L1_COMPAT + case 'v': + if (_IOC_NR(cmd) >= V4L1_IOCTLS) { + type = "v4l1"; + break; + } + printk("%s", v4l1_ioctls[_IOC_NR(cmd)]); + return; +#endif + case 'V': + if (_IOC_NR(cmd) >= V4L2_IOCTLS) { + type = "v4l2"; + break; + } + printk("%s", v4l2_ioctls[_IOC_NR(cmd)]); + return; + default: + type = "unknown"; + } + + switch (_IOC_DIR(cmd)) { + case _IOC_NONE: dir = "--"; break; + case _IOC_READ: dir = "r-"; break; + case _IOC_WRITE: dir = "-w"; break; + case _IOC_READ | _IOC_WRITE: dir = "rw"; break; + default: dir = "*ERR*"; break; + } + printk("%s ioctl '%c', dir=%s, #%d (0x%08x)", + type, _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd); +} +EXPORT_SYMBOL(v4l_printk_ioctl); + +/* + * helper function -- handles userspace copying for ioctl arguments + */ + +#ifdef __OLD_VIDIOC_ +static unsigned int +video_fix_command(unsigned int cmd) +{ + switch (cmd) { + case VIDIOC_OVERLAY_OLD: + cmd = VIDIOC_OVERLAY; + break; + case VIDIOC_S_PARM_OLD: + cmd = VIDIOC_S_PARM; + break; + case VIDIOC_S_CTRL_OLD: + cmd = VIDIOC_S_CTRL; + break; + case VIDIOC_G_AUDIO_OLD: + cmd = VIDIOC_G_AUDIO; + break; + case VIDIOC_G_AUDOUT_OLD: + cmd = VIDIOC_G_AUDOUT; + break; + case VIDIOC_CROPCAP_OLD: + cmd = VIDIOC_CROPCAP; + break; + } + return cmd; +} +#endif + +/* + * Obsolete usercopy function - Should be removed soon + */ +int +video_usercopy(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, + int (*func)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg)) +{ + char sbuf[128]; + void *mbuf = NULL; + void *parg = NULL; + int err = -EINVAL; + int is_ext_ctrl; + size_t ctrls_size = 0; + void __user *user_ptr = NULL; + +#ifdef __OLD_VIDIOC_ + cmd = video_fix_command(cmd); +#endif + is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || + cmd == VIDIOC_TRY_EXT_CTRLS); + + /* Copy arguments into temp kernel buffer */ + switch (_IOC_DIR(cmd)) { + case _IOC_NONE: + parg = NULL; + break; + case _IOC_READ: + case _IOC_WRITE: + case (_IOC_WRITE | _IOC_READ): + if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { + parg = sbuf; + } else { + /* too big to allocate from stack */ + mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL); + if (NULL == mbuf) + return -ENOMEM; + parg = mbuf; + } + + err = -EFAULT; + if (_IOC_DIR(cmd) & _IOC_WRITE) + if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) + goto out; + break; + } + if (is_ext_ctrl) { + struct v4l2_ext_controls *p = parg; + + /* In case of an error, tell the caller that it wasn't + a specific control that caused it. */ + p->error_idx = p->count; + user_ptr = (void __user *)p->controls; + if (p->count) { + ctrls_size = sizeof(struct v4l2_ext_control) * p->count; + /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ + mbuf = kmalloc(ctrls_size, GFP_KERNEL); + err = -ENOMEM; + if (NULL == mbuf) + goto out_ext_ctrl; + err = -EFAULT; + if (copy_from_user(mbuf, user_ptr, ctrls_size)) + goto out_ext_ctrl; + p->controls = mbuf; + } + } + + /* call driver */ + err = func(inode, file, cmd, parg); + if (err == -ENOIOCTLCMD) + err = -EINVAL; + if (is_ext_ctrl) { + struct v4l2_ext_controls *p = parg; + + p->controls = (void *)user_ptr; + if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) + err = -EFAULT; + goto out_ext_ctrl; + } + if (err < 0) + goto out; + +out_ext_ctrl: + /* Copy results into user buffer */ + switch (_IOC_DIR(cmd)) { + case _IOC_READ: + case (_IOC_WRITE | _IOC_READ): + if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) + err = -EFAULT; + break; + } + +out: + kfree(mbuf); + return err; +} +EXPORT_SYMBOL(video_usercopy); + +static void dbgbuf(unsigned int cmd, struct video_device *vfd, + struct v4l2_buffer *p) +{ + struct v4l2_timecode *tc = &p->timecode; + + dbgarg(cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, " + "bytesused=%d, flags=0x%08d, " + "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n", + p->timestamp.tv_sec / 3600, + (int)(p->timestamp.tv_sec / 60) % 60, + (int)(p->timestamp.tv_sec % 60), + p->timestamp.tv_usec, + p->index, + prt_names(p->type, v4l2_type_names), + p->bytesused, p->flags, + p->field, p->sequence, + prt_names(p->memory, v4l2_memory_names), + p->m.userptr, p->length); + dbgarg2("timecode=%02d:%02d:%02d type=%d, " + "flags=0x%08d, frames=%d, userbits=0x%08x\n", + tc->hours, tc->minutes, tc->seconds, + tc->type, tc->flags, tc->frames, *(__u32 *)tc->userbits); +} + +static inline void dbgrect(struct video_device *vfd, char *s, + struct v4l2_rect *r) +{ + dbgarg2("%sRect start at %dx%d, size=%dx%d\n", s, r->left, r->top, + r->width, r->height); +}; + +static inline void v4l_print_pix_fmt(struct video_device *vfd, + struct v4l2_pix_format *fmt) +{ + dbgarg2("width=%d, height=%d, format=%c%c%c%c, field=%s, " + "bytesperline=%d sizeimage=%d, colorspace=%d\n", + fmt->width, fmt->height, + (fmt->pixelformat & 0xff), + (fmt->pixelformat >> 8) & 0xff, + (fmt->pixelformat >> 16) & 0xff, + (fmt->pixelformat >> 24) & 0xff, + prt_names(fmt->field, v4l2_field_names), + fmt->bytesperline, fmt->sizeimage, fmt->colorspace); +}; + +static inline void v4l_print_ext_ctrls(unsigned int cmd, + struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals) +{ + __u32 i; + + if (!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) + return; + dbgarg(cmd, ""); + printk(KERN_CONT "class=0x%x", c->ctrl_class); + for (i = 0; i < c->count; i++) { + if (show_vals) + printk(KERN_CONT " id/val=0x%x/0x%x", + c->controls[i].id, c->controls[i].value); + else + printk(KERN_CONT " id=0x%x", c->controls[i].id); + } + printk(KERN_CONT "\n"); +}; + +static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) +{ + __u32 i; + + /* zero the reserved fields */ + c->reserved[0] = c->reserved[1] = 0; + for (i = 0; i < c->count; i++) { + c->controls[i].reserved2[0] = 0; + c->controls[i].reserved2[1] = 0; + } + /* V4L2_CID_PRIVATE_BASE cannot be used as control class + when using extended controls. + Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL + is it allowed for backwards compatibility. + */ + if (!allow_priv && c->ctrl_class == V4L2_CID_PRIVATE_BASE) + return 0; + /* Check that all controls are from the same control class. */ + for (i = 0; i < c->count; i++) { + if (V4L2_CTRL_ID2CLASS(c->controls[i].id) != c->ctrl_class) { + c->error_idx = i; + return 0; + } + } + return 1; +} + +static int check_fmt(struct video_device *vfd, enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (vfd->vidioc_try_fmt_vid_cap) + return 0; + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (vfd->vidioc_try_fmt_vid_overlay) + return 0; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (vfd->vidioc_try_fmt_vid_out) + return 0; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + if (vfd->vidioc_try_fmt_vid_out_overlay) + return 0; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (vfd->vidioc_try_fmt_vbi_cap) + return 0; + break; + case V4L2_BUF_TYPE_VBI_OUTPUT: + if (vfd->vidioc_try_fmt_vbi_out) + return 0; + break; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + if (vfd->vidioc_try_fmt_sliced_vbi_cap) + return 0; + break; + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + if (vfd->vidioc_try_fmt_sliced_vbi_out) + return 0; + break; + case V4L2_BUF_TYPE_PRIVATE: + if (vfd->vidioc_try_fmt_type_private) + return 0; + break; + } + return -EINVAL; +} + +static int __video_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct video_device *vfd = video_devdata(file); + void *fh = file->private_data; + int ret = -EINVAL; + + if ((vfd->debug & V4L2_DEBUG_IOCTL) && + !(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) { + v4l_print_ioctl(vfd->name, cmd); + printk(KERN_CONT "\n"); + } + +#ifdef CONFIG_VIDEO_V4L1_COMPAT + /*********************************************************** + Handles calls to the obsoleted V4L1 API + Due to the nature of VIDIOCGMBUF, each driver that supports + V4L1 should implement its own handler for this ioctl. + ***********************************************************/ + + /* --- streaming capture ------------------------------------- */ + if (cmd == VIDIOCGMBUF) { + struct video_mbuf *p = arg; + + memset(p, 0, sizeof(*p)); + + if (!vfd->vidiocgmbuf) + return ret; + ret = vfd->vidiocgmbuf(file, fh, p); + if (!ret) + dbgarg(cmd, "size=%d, frames=%d, offsets=0x%08lx\n", + p->size, p->frames, + (unsigned long)p->offsets); + return ret; + } + + /******************************************************** + All other V4L1 calls are handled by v4l1_compat module. + Those calls will be translated into V4L2 calls, and + __video_do_ioctl will be called again, with one or more + V4L2 ioctls. + ********************************************************/ + if (_IOC_TYPE(cmd) == 'v') + return v4l_compat_translate_ioctl(inode, file, cmd, arg, + __video_do_ioctl); +#endif + + switch (cmd) { + /* --- capabilities ------------------------------------------ */ + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *cap = (struct v4l2_capability *)arg; + memset(cap, 0, sizeof(*cap)); + + if (!vfd->vidioc_querycap) + break; + + ret = vfd->vidioc_querycap(file, fh, cap); + if (!ret) + dbgarg(cmd, "driver=%s, card=%s, bus=%s, " + "version=0x%08x, " + "capabilities=0x%08x\n", + cap->driver, cap->card, cap->bus_info, + cap->version, + cap->capabilities); + break; + } + + /* --- priority ------------------------------------------ */ + case VIDIOC_G_PRIORITY: + { + enum v4l2_priority *p = arg; + + if (!vfd->vidioc_g_priority) + break; + ret = vfd->vidioc_g_priority(file, fh, p); + if (!ret) + dbgarg(cmd, "priority is %d\n", *p); + break; + } + case VIDIOC_S_PRIORITY: + { + enum v4l2_priority *p = arg; + + if (!vfd->vidioc_s_priority) + break; + dbgarg(cmd, "setting priority to %d\n", *p); + ret = vfd->vidioc_s_priority(file, fh, *p); + break; + } + + /* --- capture ioctls ---------------------------------------- */ + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc *f = arg; + enum v4l2_buf_type type; + unsigned int index; + + index = f->index; + type = f->type; + memset(f, 0, sizeof(*f)); + f->index = index; + f->type = type; + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (vfd->vidioc_enum_fmt_vid_cap) + ret = vfd->vidioc_enum_fmt_vid_cap(file, fh, f); + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (vfd->vidioc_enum_fmt_vid_overlay) + ret = vfd->vidioc_enum_fmt_vid_overlay(file, + fh, f); + break; +#if 1 + /* V4L2_BUF_TYPE_VBI_CAPTURE should not support VIDIOC_ENUM_FMT + * according to the spec. The bttv and saa7134 drivers support + * it though, so just warn that this is deprecated and will be + * removed in the near future. */ + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (vfd->vidioc_enum_fmt_vbi_cap) { + printk(KERN_WARNING "vidioc_enum_fmt_vbi_cap will be removed in 2.6.28!\n"); + ret = vfd->vidioc_enum_fmt_vbi_cap(file, fh, f); + } + break; +#endif + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (vfd->vidioc_enum_fmt_vid_out) + ret = vfd->vidioc_enum_fmt_vid_out(file, fh, f); + break; + case V4L2_BUF_TYPE_PRIVATE: + if (vfd->vidioc_enum_fmt_type_private) + ret = vfd->vidioc_enum_fmt_type_private(file, + fh, f); + break; + default: + break; + } + if (!ret) + dbgarg(cmd, "index=%d, type=%d, flags=%d, " + "pixelformat=%c%c%c%c, description='%s'\n", + f->index, f->type, f->flags, + (f->pixelformat & 0xff), + (f->pixelformat >> 8) & 0xff, + (f->pixelformat >> 16) & 0xff, + (f->pixelformat >> 24) & 0xff, + f->description); + break; + } + case VIDIOC_G_FMT: + { + struct v4l2_format *f = (struct v4l2_format *)arg; + + memset(f->fmt.raw_data, 0, sizeof(f->fmt.raw_data)); + + /* FIXME: Should be one dump per type */ + dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (vfd->vidioc_g_fmt_vid_cap) + ret = vfd->vidioc_g_fmt_vid_cap(file, fh, f); + if (!ret) + v4l_print_pix_fmt(vfd, &f->fmt.pix); + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (vfd->vidioc_g_fmt_vid_overlay) + ret = vfd->vidioc_g_fmt_vid_overlay(file, + fh, f); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (vfd->vidioc_g_fmt_vid_out) + ret = vfd->vidioc_g_fmt_vid_out(file, fh, f); + if (!ret) + v4l_print_pix_fmt(vfd, &f->fmt.pix); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + if (vfd->vidioc_g_fmt_vid_out_overlay) + ret = vfd->vidioc_g_fmt_vid_out_overlay(file, + fh, f); + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (vfd->vidioc_g_fmt_vbi_cap) + ret = vfd->vidioc_g_fmt_vbi_cap(file, fh, f); + break; + case V4L2_BUF_TYPE_VBI_OUTPUT: + if (vfd->vidioc_g_fmt_vbi_out) + ret = vfd->vidioc_g_fmt_vbi_out(file, fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + if (vfd->vidioc_g_fmt_sliced_vbi_cap) + ret = vfd->vidioc_g_fmt_sliced_vbi_cap(file, + fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + if (vfd->vidioc_g_fmt_sliced_vbi_out) + ret = vfd->vidioc_g_fmt_sliced_vbi_out(file, + fh, f); + break; + case V4L2_BUF_TYPE_PRIVATE: + if (vfd->vidioc_g_fmt_type_private) + ret = vfd->vidioc_g_fmt_type_private(file, + fh, f); + break; + } + + break; + } + case VIDIOC_S_FMT: + { + struct v4l2_format *f = (struct v4l2_format *)arg; + + /* FIXME: Should be one dump per type */ + dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + v4l_print_pix_fmt(vfd, &f->fmt.pix); + if (vfd->vidioc_s_fmt_vid_cap) + ret = vfd->vidioc_s_fmt_vid_cap(file, fh, f); + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (vfd->vidioc_s_fmt_vid_overlay) + ret = vfd->vidioc_s_fmt_vid_overlay(file, + fh, f); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + v4l_print_pix_fmt(vfd, &f->fmt.pix); + if (vfd->vidioc_s_fmt_vid_out) + ret = vfd->vidioc_s_fmt_vid_out(file, fh, f); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + if (vfd->vidioc_s_fmt_vid_out_overlay) + ret = vfd->vidioc_s_fmt_vid_out_overlay(file, + fh, f); + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (vfd->vidioc_s_fmt_vbi_cap) + ret = vfd->vidioc_s_fmt_vbi_cap(file, fh, f); + break; + case V4L2_BUF_TYPE_VBI_OUTPUT: + if (vfd->vidioc_s_fmt_vbi_out) + ret = vfd->vidioc_s_fmt_vbi_out(file, fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + if (vfd->vidioc_s_fmt_sliced_vbi_cap) + ret = vfd->vidioc_s_fmt_sliced_vbi_cap(file, + fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + if (vfd->vidioc_s_fmt_sliced_vbi_out) + ret = vfd->vidioc_s_fmt_sliced_vbi_out(file, + fh, f); + break; + case V4L2_BUF_TYPE_PRIVATE: + if (vfd->vidioc_s_fmt_type_private) + ret = vfd->vidioc_s_fmt_type_private(file, + fh, f); + break; + } + break; + } + case VIDIOC_TRY_FMT: + { + struct v4l2_format *f = (struct v4l2_format *)arg; + + /* FIXME: Should be one dump per type */ + dbgarg(cmd, "type=%s\n", prt_names(f->type, + v4l2_type_names)); + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (vfd->vidioc_try_fmt_vid_cap) + ret = vfd->vidioc_try_fmt_vid_cap(file, fh, f); + if (!ret) + v4l_print_pix_fmt(vfd, &f->fmt.pix); + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (vfd->vidioc_try_fmt_vid_overlay) + ret = vfd->vidioc_try_fmt_vid_overlay(file, + fh, f); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (vfd->vidioc_try_fmt_vid_out) + ret = vfd->vidioc_try_fmt_vid_out(file, fh, f); + if (!ret) + v4l_print_pix_fmt(vfd, &f->fmt.pix); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + if (vfd->vidioc_try_fmt_vid_out_overlay) + ret = vfd->vidioc_try_fmt_vid_out_overlay(file, + fh, f); + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (vfd->vidioc_try_fmt_vbi_cap) + ret = vfd->vidioc_try_fmt_vbi_cap(file, fh, f); + break; + case V4L2_BUF_TYPE_VBI_OUTPUT: + if (vfd->vidioc_try_fmt_vbi_out) + ret = vfd->vidioc_try_fmt_vbi_out(file, fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + if (vfd->vidioc_try_fmt_sliced_vbi_cap) + ret = vfd->vidioc_try_fmt_sliced_vbi_cap(file, + fh, f); + break; + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + if (vfd->vidioc_try_fmt_sliced_vbi_out) + ret = vfd->vidioc_try_fmt_sliced_vbi_out(file, + fh, f); + break; + case V4L2_BUF_TYPE_PRIVATE: + if (vfd->vidioc_try_fmt_type_private) + ret = vfd->vidioc_try_fmt_type_private(file, + fh, f); + break; + } + + break; + } + /* FIXME: Those buf reqs could be handled here, + with some changes on videobuf to allow its header to be included at + videodev2.h or being merged at videodev2. + */ + case VIDIOC_REQBUFS: + { + struct v4l2_requestbuffers *p = arg; + + if (!vfd->vidioc_reqbufs) + break; + ret = check_fmt(vfd, p->type); + if (ret) + break; + + ret = vfd->vidioc_reqbufs(file, fh, p); + dbgarg(cmd, "count=%d, type=%s, memory=%s\n", + p->count, + prt_names(p->type, v4l2_type_names), + prt_names(p->memory, v4l2_memory_names)); + break; + } + case VIDIOC_QUERYBUF: + { + struct v4l2_buffer *p = arg; + + if (!vfd->vidioc_querybuf) + break; + ret = check_fmt(vfd, p->type); + if (ret) + break; + + ret = vfd->vidioc_querybuf(file, fh, p); + if (!ret) + dbgbuf(cmd, vfd, p); + break; + } + case VIDIOC_QBUF: + { + struct v4l2_buffer *p = arg; + + if (!vfd->vidioc_qbuf) + break; + ret = check_fmt(vfd, p->type); + if (ret) + break; + + ret = vfd->vidioc_qbuf(file, fh, p); + if (!ret) + dbgbuf(cmd, vfd, p); + break; + } + case VIDIOC_DQBUF: + { + struct v4l2_buffer *p = arg; + + if (!vfd->vidioc_dqbuf) + break; + ret = check_fmt(vfd, p->type); + if (ret) + break; + + ret = vfd->vidioc_dqbuf(file, fh, p); + if (!ret) + dbgbuf(cmd, vfd, p); + break; + } + case VIDIOC_OVERLAY: + { + int *i = arg; + + if (!vfd->vidioc_overlay) + break; + dbgarg(cmd, "value=%d\n", *i); + ret = vfd->vidioc_overlay(file, fh, *i); + break; + } + case VIDIOC_G_FBUF: + { + struct v4l2_framebuffer *p = arg; + + if (!vfd->vidioc_g_fbuf) + break; + ret = vfd->vidioc_g_fbuf(file, fh, arg); + if (!ret) { + dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", + p->capability, p->flags, + (unsigned long)p->base); + v4l_print_pix_fmt(vfd, &p->fmt); + } + break; + } + case VIDIOC_S_FBUF: + { + struct v4l2_framebuffer *p = arg; + + if (!vfd->vidioc_s_fbuf) + break; + dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", + p->capability, p->flags, (unsigned long)p->base); + v4l_print_pix_fmt(vfd, &p->fmt); + ret = vfd->vidioc_s_fbuf(file, fh, arg); + break; + } + case VIDIOC_STREAMON: + { + enum v4l2_buf_type i = *(int *)arg; + + if (!vfd->vidioc_streamon) + break; + dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); + ret = vfd->vidioc_streamon(file, fh, i); + break; + } + case VIDIOC_STREAMOFF: + { + enum v4l2_buf_type i = *(int *)arg; + + if (!vfd->vidioc_streamoff) + break; + dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); + ret = vfd->vidioc_streamoff(file, fh, i); + break; + } + /* ---------- tv norms ---------- */ + case VIDIOC_ENUMSTD: + { + struct v4l2_standard *p = arg; + v4l2_std_id id = vfd->tvnorms, curr_id = 0; + unsigned int index = p->index, i, j = 0; + const char *descr = ""; + + /* Return norm array in a canonical way */ + for (i = 0; i <= index && id; i++) { + /* last std value in the standards array is 0, so this + while always ends there since (id & 0) == 0. */ + while ((id & standards[j].std) != standards[j].std) + j++; + curr_id = standards[j].std; + descr = standards[j].descr; + j++; + if (curr_id == 0) + break; + if (curr_id != V4L2_STD_PAL && + curr_id != V4L2_STD_SECAM && + curr_id != V4L2_STD_NTSC) + id &= ~curr_id; + } + if (i <= index) + return -EINVAL; + + v4l2_video_std_construct(p, curr_id, descr); + p->index = index; + + dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, " + "framelines=%d\n", p->index, + (unsigned long long)p->id, p->name, + p->frameperiod.numerator, + p->frameperiod.denominator, + p->framelines); + + ret = 0; + break; + } + case VIDIOC_G_STD: + { + v4l2_std_id *id = arg; + + ret = 0; + /* Calls the specific handler */ + if (vfd->vidioc_g_std) + ret = vfd->vidioc_g_std(file, fh, id); + else + *id = vfd->current_norm; + + if (!ret) + dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id); + break; + } + case VIDIOC_S_STD: + { + v4l2_std_id *id = arg, norm; + + dbgarg(cmd, "std=%08Lx\n", (long long unsigned)*id); + + norm = (*id) & vfd->tvnorms; + if (vfd->tvnorms && !norm) /* Check if std is supported */ + break; + + /* Calls the specific handler */ + if (vfd->vidioc_s_std) + ret = vfd->vidioc_s_std(file, fh, &norm); + else + ret = -EINVAL; + + /* Updates standard information */ + if (ret >= 0) + vfd->current_norm = norm; + break; + } + case VIDIOC_QUERYSTD: + { + v4l2_std_id *p = arg; + + if (!vfd->vidioc_querystd) + break; + ret = vfd->vidioc_querystd(file, fh, arg); + if (!ret) + dbgarg(cmd, "detected std=%08Lx\n", + (unsigned long long)*p); + break; + } + /* ------ input switching ---------- */ + /* FIXME: Inputs can be handled inside videodev2 */ + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *p = arg; + int i = p->index; + + if (!vfd->vidioc_enum_input) + break; + memset(p, 0, sizeof(*p)); + p->index = i; + + ret = vfd->vidioc_enum_input(file, fh, p); + if (!ret) + dbgarg(cmd, "index=%d, name=%s, type=%d, " + "audioset=%d, " + "tuner=%d, std=%08Lx, status=%d\n", + p->index, p->name, p->type, p->audioset, + p->tuner, + (unsigned long long)p->std, + p->status); + break; + } + case VIDIOC_G_INPUT: + { + unsigned int *i = arg; + + if (!vfd->vidioc_g_input) + break; + ret = vfd->vidioc_g_input(file, fh, i); + if (!ret) + dbgarg(cmd, "value=%d\n", *i); + break; + } + case VIDIOC_S_INPUT: + { + unsigned int *i = arg; + + if (!vfd->vidioc_s_input) + break; + dbgarg(cmd, "value=%d\n", *i); + ret = vfd->vidioc_s_input(file, fh, *i); + break; + } + + /* ------ output switching ---------- */ + case VIDIOC_ENUMOUTPUT: + { + struct v4l2_output *p = arg; + int i = p->index; + + if (!vfd->vidioc_enum_output) + break; + memset(p, 0, sizeof(*p)); + p->index = i; + + ret = vfd->vidioc_enum_output(file, fh, p); + if (!ret) + dbgarg(cmd, "index=%d, name=%s, type=%d, " + "audioset=0x%x, " + "modulator=%d, std=0x%08Lx\n", + p->index, p->name, p->type, p->audioset, + p->modulator, (unsigned long long)p->std); + break; + } + case VIDIOC_G_OUTPUT: + { + unsigned int *i = arg; + + if (!vfd->vidioc_g_output) + break; + ret = vfd->vidioc_g_output(file, fh, i); + if (!ret) + dbgarg(cmd, "value=%d\n", *i); + break; + } + case VIDIOC_S_OUTPUT: + { + unsigned int *i = arg; + + if (!vfd->vidioc_s_output) + break; + dbgarg(cmd, "value=%d\n", *i); + ret = vfd->vidioc_s_output(file, fh, *i); + break; + } + + /* --- controls ---------------------------------------------- */ + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *p = arg; + + if (!vfd->vidioc_queryctrl) + break; + ret = vfd->vidioc_queryctrl(file, fh, p); + if (!ret) + dbgarg(cmd, "id=0x%x, type=%d, name=%s, min/max=%d/%d, " + "step=%d, default=%d, flags=0x%08x\n", + p->id, p->type, p->name, + p->minimum, p->maximum, + p->step, p->default_value, p->flags); + else + dbgarg(cmd, "id=0x%x\n", p->id); + break; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *p = arg; + + if (vfd->vidioc_g_ctrl) + ret = vfd->vidioc_g_ctrl(file, fh, p); + else if (vfd->vidioc_g_ext_ctrls) { + struct v4l2_ext_controls ctrls; + struct v4l2_ext_control ctrl; + + ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); + ctrls.count = 1; + ctrls.controls = &ctrl; + ctrl.id = p->id; + ctrl.value = p->value; + if (check_ext_ctrls(&ctrls, 1)) { + ret = vfd->vidioc_g_ext_ctrls(file, fh, &ctrls); + if (ret == 0) + p->value = ctrl.value; + } + } else + break; + if (!ret) + dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); + else + dbgarg(cmd, "id=0x%x\n", p->id); + break; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *p = arg; + struct v4l2_ext_controls ctrls; + struct v4l2_ext_control ctrl; + + if (!vfd->vidioc_s_ctrl && !vfd->vidioc_s_ext_ctrls) + break; + + dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); + + if (vfd->vidioc_s_ctrl) { + ret = vfd->vidioc_s_ctrl(file, fh, p); + break; + } + if (!vfd->vidioc_s_ext_ctrls) + break; + + ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); + ctrls.count = 1; + ctrls.controls = &ctrl; + ctrl.id = p->id; + ctrl.value = p->value; + if (check_ext_ctrls(&ctrls, 1)) + ret = vfd->vidioc_s_ext_ctrls(file, fh, &ctrls); + break; + } + case VIDIOC_G_EXT_CTRLS: + { + struct v4l2_ext_controls *p = arg; + + p->error_idx = p->count; + if (!vfd->vidioc_g_ext_ctrls) + break; + if (check_ext_ctrls(p, 0)) + ret = vfd->vidioc_g_ext_ctrls(file, fh, p); + v4l_print_ext_ctrls(cmd, vfd, p, !ret); + break; + } + case VIDIOC_S_EXT_CTRLS: + { + struct v4l2_ext_controls *p = arg; + + p->error_idx = p->count; + if (!vfd->vidioc_s_ext_ctrls) + break; + v4l_print_ext_ctrls(cmd, vfd, p, 1); + if (check_ext_ctrls(p, 0)) + ret = vfd->vidioc_s_ext_ctrls(file, fh, p); + break; + } + case VIDIOC_TRY_EXT_CTRLS: + { + struct v4l2_ext_controls *p = arg; + + p->error_idx = p->count; + if (!vfd->vidioc_try_ext_ctrls) + break; + v4l_print_ext_ctrls(cmd, vfd, p, 1); + if (check_ext_ctrls(p, 0)) + ret = vfd->vidioc_try_ext_ctrls(file, fh, p); + break; + } + case VIDIOC_QUERYMENU: + { + struct v4l2_querymenu *p = arg; + + if (!vfd->vidioc_querymenu) + break; + ret = vfd->vidioc_querymenu(file, fh, p); + if (!ret) + dbgarg(cmd, "id=0x%x, index=%d, name=%s\n", + p->id, p->index, p->name); + else + dbgarg(cmd, "id=0x%x, index=%d\n", + p->id, p->index); + break; + } + /* --- audio ---------------------------------------------- */ + case VIDIOC_ENUMAUDIO: + { + struct v4l2_audio *p = arg; + + if (!vfd->vidioc_enumaudio) + break; + ret = vfd->vidioc_enumaudio(file, fh, p); + if (!ret) + dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " + "mode=0x%x\n", p->index, p->name, + p->capability, p->mode); + else + dbgarg(cmd, "index=%d\n", p->index); + break; + } + case VIDIOC_G_AUDIO: + { + struct v4l2_audio *p = arg; + __u32 index = p->index; + + if (!vfd->vidioc_g_audio) + break; + + memset(p, 0, sizeof(*p)); + p->index = index; + ret = vfd->vidioc_g_audio(file, fh, p); + if (!ret) + dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " + "mode=0x%x\n", p->index, + p->name, p->capability, p->mode); + else + dbgarg(cmd, "index=%d\n", p->index); + break; + } + case VIDIOC_S_AUDIO: + { + struct v4l2_audio *p = arg; + + if (!vfd->vidioc_s_audio) + break; + dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " + "mode=0x%x\n", p->index, p->name, + p->capability, p->mode); + ret = vfd->vidioc_s_audio(file, fh, p); + break; + } + case VIDIOC_ENUMAUDOUT: + { + struct v4l2_audioout *p = arg; + + if (!vfd->vidioc_enumaudout) + break; + dbgarg(cmd, "Enum for index=%d\n", p->index); + ret = vfd->vidioc_enumaudout(file, fh, p); + if (!ret) + dbgarg2("index=%d, name=%s, capability=%d, " + "mode=%d\n", p->index, p->name, + p->capability, p->mode); + break; + } + case VIDIOC_G_AUDOUT: + { + struct v4l2_audioout *p = arg; + + if (!vfd->vidioc_g_audout) + break; + dbgarg(cmd, "Enum for index=%d\n", p->index); + ret = vfd->vidioc_g_audout(file, fh, p); + if (!ret) + dbgarg2("index=%d, name=%s, capability=%d, " + "mode=%d\n", p->index, p->name, + p->capability, p->mode); + break; + } + case VIDIOC_S_AUDOUT: + { + struct v4l2_audioout *p = arg; + + if (!vfd->vidioc_s_audout) + break; + dbgarg(cmd, "index=%d, name=%s, capability=%d, " + "mode=%d\n", p->index, p->name, + p->capability, p->mode); + + ret = vfd->vidioc_s_audout(file, fh, p); + break; + } + case VIDIOC_G_MODULATOR: + { + struct v4l2_modulator *p = arg; + + if (!vfd->vidioc_g_modulator) + break; + ret = vfd->vidioc_g_modulator(file, fh, p); + if (!ret) + dbgarg(cmd, "index=%d, name=%s, " + "capability=%d, rangelow=%d," + " rangehigh=%d, txsubchans=%d\n", + p->index, p->name, p->capability, + p->rangelow, p->rangehigh, + p->txsubchans); + break; + } + case VIDIOC_S_MODULATOR: + { + struct v4l2_modulator *p = arg; + + if (!vfd->vidioc_s_modulator) + break; + dbgarg(cmd, "index=%d, name=%s, capability=%d, " + "rangelow=%d, rangehigh=%d, txsubchans=%d\n", + p->index, p->name, p->capability, p->rangelow, + p->rangehigh, p->txsubchans); + ret = vfd->vidioc_s_modulator(file, fh, p); + break; + } + case VIDIOC_G_CROP: + { + struct v4l2_crop *p = arg; + + if (!vfd->vidioc_g_crop) + break; + dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); + ret = vfd->vidioc_g_crop(file, fh, p); + if (!ret) + dbgrect(vfd, "", &p->c); + break; + } + case VIDIOC_S_CROP: + { + struct v4l2_crop *p = arg; + + if (!vfd->vidioc_s_crop) + break; + dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); + dbgrect(vfd, "", &p->c); + ret = vfd->vidioc_s_crop(file, fh, p); + break; + } + case VIDIOC_CROPCAP: + { + struct v4l2_cropcap *p = arg; + + /*FIXME: Should also show v4l2_fract pixelaspect */ + if (!vfd->vidioc_cropcap) + break; + dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); + ret = vfd->vidioc_cropcap(file, fh, p); + if (!ret) { + dbgrect(vfd, "bounds ", &p->bounds); + dbgrect(vfd, "defrect ", &p->defrect); + } + break; + } + case VIDIOC_G_JPEGCOMP: + { + struct v4l2_jpegcompression *p = arg; + + if (!vfd->vidioc_g_jpegcomp) + break; + ret = vfd->vidioc_g_jpegcomp(file, fh, p); + if (!ret) + dbgarg(cmd, "quality=%d, APPn=%d, " + "APP_len=%d, COM_len=%d, " + "jpeg_markers=%d\n", + p->quality, p->APPn, p->APP_len, + p->COM_len, p->jpeg_markers); + break; + } + case VIDIOC_S_JPEGCOMP: + { + struct v4l2_jpegcompression *p = arg; + + if (!vfd->vidioc_g_jpegcomp) + break; + dbgarg(cmd, "quality=%d, APPn=%d, APP_len=%d, " + "COM_len=%d, jpeg_markers=%d\n", + p->quality, p->APPn, p->APP_len, + p->COM_len, p->jpeg_markers); + ret = vfd->vidioc_s_jpegcomp(file, fh, p); + break; + } + case VIDIOC_G_ENC_INDEX: + { + struct v4l2_enc_idx *p = arg; + + if (!vfd->vidioc_g_enc_index) + break; + ret = vfd->vidioc_g_enc_index(file, fh, p); + if (!ret) + dbgarg(cmd, "entries=%d, entries_cap=%d\n", + p->entries, p->entries_cap); + break; + } + case VIDIOC_ENCODER_CMD: + { + struct v4l2_encoder_cmd *p = arg; + + if (!vfd->vidioc_encoder_cmd) + break; + memset(&p->raw, 0, sizeof(p->raw)); + ret = vfd->vidioc_encoder_cmd(file, fh, p); + if (!ret) + dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); + break; + } + case VIDIOC_TRY_ENCODER_CMD: + { + struct v4l2_encoder_cmd *p = arg; + + if (!vfd->vidioc_try_encoder_cmd) + break; + memset(&p->raw, 0, sizeof(p->raw)); + ret = vfd->vidioc_try_encoder_cmd(file, fh, p); + if (!ret) + dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); + break; + } + case VIDIOC_G_PARM: + { + struct v4l2_streamparm *p = arg; + __u32 type = p->type; + + memset(p, 0, sizeof(*p)); + p->type = type; + + if (vfd->vidioc_g_parm) { + ret = vfd->vidioc_g_parm(file, fh, p); + } else { + struct v4l2_standard s; + + if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + v4l2_video_std_construct(&s, vfd->current_norm, + v4l2_norm_to_name(vfd->current_norm)); + + p->parm.capture.timeperframe = s.frameperiod; + ret = 0; + } + + dbgarg(cmd, "type=%d\n", p->type); + break; + } + case VIDIOC_S_PARM: + { + struct v4l2_streamparm *p = arg; + + if (!vfd->vidioc_s_parm) + break; + dbgarg(cmd, "type=%d\n", p->type); + ret = vfd->vidioc_s_parm(file, fh, p); + break; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *p = arg; + __u32 index = p->index; + + if (!vfd->vidioc_g_tuner) + break; + + memset(p, 0, sizeof(*p)); + p->index = index; + + ret = vfd->vidioc_g_tuner(file, fh, p); + if (!ret) + dbgarg(cmd, "index=%d, name=%s, type=%d, " + "capability=0x%x, rangelow=%d, " + "rangehigh=%d, signal=%d, afc=%d, " + "rxsubchans=0x%x, audmode=%d\n", + p->index, p->name, p->type, + p->capability, p->rangelow, + p->rangehigh, p->signal, p->afc, + p->rxsubchans, p->audmode); + break; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *p = arg; + + if (!vfd->vidioc_s_tuner) + break; + dbgarg(cmd, "index=%d, name=%s, type=%d, " + "capability=0x%x, rangelow=%d, " + "rangehigh=%d, signal=%d, afc=%d, " + "rxsubchans=0x%x, audmode=%d\n", + p->index, p->name, p->type, + p->capability, p->rangelow, + p->rangehigh, p->signal, p->afc, + p->rxsubchans, p->audmode); + ret = vfd->vidioc_s_tuner(file, fh, p); + break; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *p = arg; + + if (!vfd->vidioc_g_frequency) + break; + + memset(p->reserved, 0, sizeof(p->reserved)); + + ret = vfd->vidioc_g_frequency(file, fh, p); + if (!ret) + dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", + p->tuner, p->type, p->frequency); + break; + } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *p = arg; + + if (!vfd->vidioc_s_frequency) + break; + dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", + p->tuner, p->type, p->frequency); + ret = vfd->vidioc_s_frequency(file, fh, p); + break; + } + case VIDIOC_G_SLICED_VBI_CAP: + { + struct v4l2_sliced_vbi_cap *p = arg; + __u32 type = p->type; + + if (!vfd->vidioc_g_sliced_vbi_cap) + break; + memset(p, 0, sizeof(*p)); + p->type = type; + dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); + ret = vfd->vidioc_g_sliced_vbi_cap(file, fh, p); + if (!ret) + dbgarg2("service_set=%d\n", p->service_set); + break; + } + case VIDIOC_LOG_STATUS: + { + if (!vfd->vidioc_log_status) + break; + ret = vfd->vidioc_log_status(file, fh); + break; + } +#ifdef CONFIG_VIDEO_ADV_DEBUG + case VIDIOC_DBG_G_REGISTER: + { + struct v4l2_register *p = arg; + + if (!capable(CAP_SYS_ADMIN)) + ret = -EPERM; + else if (vfd->vidioc_g_register) + ret = vfd->vidioc_g_register(file, fh, p); + break; + } + case VIDIOC_DBG_S_REGISTER: + { + struct v4l2_register *p = arg; + + if (!capable(CAP_SYS_ADMIN)) + ret = -EPERM; + else if (vfd->vidioc_s_register) + ret = vfd->vidioc_s_register(file, fh, p); + break; + } +#endif + case VIDIOC_G_CHIP_IDENT: + { + struct v4l2_chip_ident *p = arg; + + if (!vfd->vidioc_g_chip_ident) + break; + ret = vfd->vidioc_g_chip_ident(file, fh, p); + if (!ret) + dbgarg(cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision); + break; + } + default: + { + if (!vfd->vidioc_default) + break; + ret = vfd->vidioc_default(file, fh, cmd, arg); + break; + } + case VIDIOC_S_HW_FREQ_SEEK: + { + struct v4l2_hw_freq_seek *p = arg; + + if (!vfd->vidioc_s_hw_freq_seek) + break; + dbgarg(cmd, + "tuner=%d, type=%d, seek_upward=%d, wrap_around=%d\n", + p->tuner, p->type, p->seek_upward, p->wrap_around); + ret = vfd->vidioc_s_hw_freq_seek(file, fh, p); + break; + } + } /* switch */ + + if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { + if (ret < 0) { + v4l_print_ioctl(vfd->name, cmd); + printk(KERN_CONT " error %d\n", ret); + } + } + + return ret; +} + +int video_ioctl2(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + char sbuf[128]; + void *mbuf = NULL; + void *parg = NULL; + int err = -EINVAL; + int is_ext_ctrl; + size_t ctrls_size = 0; + void __user *user_ptr = NULL; + +#ifdef __OLD_VIDIOC_ + cmd = video_fix_command(cmd); +#endif + is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || + cmd == VIDIOC_TRY_EXT_CTRLS); + + /* Copy arguments into temp kernel buffer */ + switch (_IOC_DIR(cmd)) { + case _IOC_NONE: + parg = NULL; + break; + case _IOC_READ: + case _IOC_WRITE: + case (_IOC_WRITE | _IOC_READ): + if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { + parg = sbuf; + } else { + /* too big to allocate from stack */ + mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL); + if (NULL == mbuf) + return -ENOMEM; + parg = mbuf; + } + + err = -EFAULT; + if (_IOC_DIR(cmd) & _IOC_WRITE) + if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) + goto out; + break; + } + + if (is_ext_ctrl) { + struct v4l2_ext_controls *p = parg; + + /* In case of an error, tell the caller that it wasn't + a specific control that caused it. */ + p->error_idx = p->count; + user_ptr = (void __user *)p->controls; + if (p->count) { + ctrls_size = sizeof(struct v4l2_ext_control) * p->count; + /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ + mbuf = kmalloc(ctrls_size, GFP_KERNEL); + err = -ENOMEM; + if (NULL == mbuf) + goto out_ext_ctrl; + err = -EFAULT; + if (copy_from_user(mbuf, user_ptr, ctrls_size)) + goto out_ext_ctrl; + p->controls = mbuf; + } + } + + /* Handles IOCTL */ + err = __video_do_ioctl(inode, file, cmd, parg); + if (err == -ENOIOCTLCMD) + err = -EINVAL; + if (is_ext_ctrl) { + struct v4l2_ext_controls *p = parg; + + p->controls = (void *)user_ptr; + if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) + err = -EFAULT; + goto out_ext_ctrl; + } + if (err < 0) + goto out; + +out_ext_ctrl: + /* Copy results into user buffer */ + switch (_IOC_DIR(cmd)) { + case _IOC_READ: + case (_IOC_WRITE | _IOC_READ): + if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) + err = -EFAULT; + break; + } + +out: + kfree(mbuf); + return err; +} +EXPORT_SYMBOL(video_ioctl2); diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 059b01c11dc..e4b3a006c71 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c index 33f702698a5..a63e11f8399 100644 --- a/drivers/media/video/w9966.c +++ b/drivers/media/video/w9966.c @@ -59,6 +59,7 @@ #include #include #include +#include #include /*#define DEBUG*/ /* Undef me for production */ diff --git a/drivers/media/video/zc0301/zc0301.h b/drivers/media/video/zc0301/zc0301.h index 7bbab541a30..b1b5cceb4ba 100644 --- a/drivers/media/video/zc0301/zc0301.h +++ b/drivers/media/video/zc0301/zc0301.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index c0675921fe2..e1e1b19a0ae 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -71,6 +71,7 @@ #include #include +#include #include "videocodec.h" #include diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c index 485df2e3613..ea5265c2298 100644 --- a/drivers/media/video/zr364xx.c +++ b/drivers/media/video/zr364xx.c @@ -35,6 +35,7 @@ #include #include #include +#include /* Version Information */ -- cgit v1.2.3 From 2864462eaf027ff10c1df1ce57d3518332e9083c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 20 Jul 2008 20:26:54 -0300 Subject: V4L/DVB (8434): Fix x86_64 compilation and move some macros to v4l2-ioctl.h Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/compat_ioctl32.c | 2 +- drivers/media/video/stradis.c | 1 + drivers/media/video/w9968cf.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c index 54de0cd482e..bd5d9de5a00 100644 --- a/drivers/media/video/compat_ioctl32.c +++ b/drivers/media/video/compat_ioctl32.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #ifdef CONFIG_COMPAT diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c index c109511f21e..6ace8923b79 100644 --- a/drivers/media/video/stradis.c +++ b/drivers/media/video/stradis.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "saa7146.h" #include "saa7146reg.h" diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 3f5a59dc5f8..56bbeec542c 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -42,6 +42,7 @@ #include #include #include +#include #include "w9968cf.h" #include "w9968cf_decoder.h" -- cgit v1.2.3 From 600176176101fc6e0e0c7468efa83203e8d3e015 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Fri, 18 Jul 2008 08:46:19 -0300 Subject: V4L/DVB (8435): gspca: Delay after reset for ov7660 and USB traces in sonixj. Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 246 ++++++++++++++++++------------------- 1 file changed, 118 insertions(+), 128 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 3e68b992695..aa4d10b823e 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -361,6 +361,7 @@ static const __u8 mo4000_sensor_init[][8] = { }; static const __u8 ov7660_sensor_init[][8] = { {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */ +/* (delay 20ms) */ {0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10}, /* Outformat ?? rawRGB */ {0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */ @@ -539,13 +540,31 @@ static void reg_r(struct gspca_dev *gspca_dev, value, 0, gspca_dev->usb_buf, len, 500); + PDEBUG(D_USBI, "reg_r [%02x] -> %02x", value, gspca_dev->usb_buf[0]); } +static void reg_w1(struct gspca_dev *gspca_dev, + __u16 value, + __u8 data) +{ + PDEBUG(D_USBO, "reg_w1 [%02x] = %02x", value, data); + gspca_dev->usb_buf[0] = data; + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, + 0, + gspca_dev->usb_buf, 1, + 500); +} static void reg_w(struct gspca_dev *gspca_dev, __u16 value, const __u8 *buffer, int len) { + PDEBUG(D_USBO, "reg_w [%02x] = %02x %02x ..", + value, buffer[0], buffer[1]); if (len <= sizeof gspca_dev->usb_buf) { memcpy(gspca_dev->usb_buf, buffer, len); usb_control_msg(gspca_dev->dev, @@ -571,31 +590,42 @@ static void reg_w(struct gspca_dev *gspca_dev, } } -/* I2C write 2 bytes */ -static void i2c_w2(struct gspca_dev *gspca_dev, - const __u8 *buffer) +/* I2C write 1 byte */ +static void i2c_w1(struct gspca_dev *gspca_dev, __u8 reg, __u8 val) { struct sd *sd = (struct sd *) gspca_dev; - __u8 mode[8]; - /* is i2c ready */ - mode[0] = 0x81 | (2 << 4); - mode[1] = sd->i2c_base; - mode[2] = buffer[0]; - mode[3] = buffer[1]; - mode[4] = 0; - mode[5] = 0; - mode[6] = 0; - mode[7] = 0x10; - reg_w(gspca_dev, 0x08, mode, 8); + PDEBUG(D_USBO, "i2c_w2 [%02x] = %02x", reg, val); + gspca_dev->usb_buf[0] = 0x81 | (2 << 4); /* = a1 */ + gspca_dev->usb_buf[1] = sd->i2c_base; + gspca_dev->usb_buf[2] = reg; + gspca_dev->usb_buf[3] = val; + gspca_dev->usb_buf[4] = 0; + gspca_dev->usb_buf[5] = 0; + gspca_dev->usb_buf[6] = 0; + gspca_dev->usb_buf[7] = 0x10; + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 0x08, /* value = i2c */ + 0, + gspca_dev->usb_buf, 8, + 500); } /* I2C write 8 bytes */ static void i2c_w8(struct gspca_dev *gspca_dev, const __u8 *buffer) { - reg_w(gspca_dev, 0x08, buffer, 8); - msleep(1); + memcpy(gspca_dev->usb_buf, buffer, 8); + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + 0x08, 0, /* value, index */ + gspca_dev->usb_buf, 8, + 500); } /* read 5 bytes in gspca_dev->usb_buf */ @@ -613,24 +643,21 @@ static void i2c_r5(struct gspca_dev *gspca_dev, __u8 reg) mode[6] = 0; mode[7] = 0x10; i2c_w8(gspca_dev, mode); + msleep(2); mode[0] = 0x81 | (5 << 4) | 0x02; mode[2] = 0; i2c_w8(gspca_dev, mode); + msleep(2); reg_r(gspca_dev, 0x0a, 5); } static int probesensor(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - __u8 reg02; - static const __u8 datasend[] = { 2, 0 }; - /* reg val1 val2 val3 val4 */ - i2c_w2(gspca_dev, datasend); -/* should write 0xa1 0x11 0x02 0x00 0x00 0x00 0x00 the 0x10 is add by i2cw */ + i2c_w1(gspca_dev, 0x02, 0); /* sensor wakeup */ msleep(10); - reg02 = 0x66; - reg_w(gspca_dev, 0x02, ®02, 1); /* Gpio on */ + reg_w1(gspca_dev, 0x02, 0x66); /* Gpio on */ msleep(10); i2c_r5(gspca_dev, 0); /* read sensor id */ if (gspca_dev->usb_buf[0] == 0x02 @@ -642,7 +669,7 @@ static int probesensor(struct gspca_dev *gspca_dev) sd->sensor = SENSOR_HV7131R; return SENSOR_HV7131R; } - PDEBUG(D_PROBE, "Find Sensor %d %d %d", + PDEBUG(D_PROBE, "Find Sensor 0x%02x 0x%02x 0x%02x", gspca_dev->usb_buf[0], gspca_dev->usb_buf[1], gspca_dev->usb_buf[2]); PDEBUG(D_PROBE, "Sensor sn9c102P Not found"); @@ -653,8 +680,6 @@ static int configure_gpio(struct gspca_dev *gspca_dev, const __u8 *sn9c1xx) { struct sd *sd = (struct sd *) gspca_dev; - __u8 data; - __u8 regF1; const __u8 *reg9a; static const __u8 reg9a_def[] = {0x08, 0x40, 0x20, 0x10, 0x00, 0x04}; @@ -663,15 +688,13 @@ static int configure_gpio(struct gspca_dev *gspca_dev, static const __u8 reg9a_sn9c325[] = {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20}; - - regF1 = 0x00; - reg_w(gspca_dev, 0xf1, ®F1, 1); - reg_w(gspca_dev, 0x01, &sn9c1xx[0], 1); /*fixme:jfm was [1] en v1*/ + reg_w1(gspca_dev, 0xf1, 0x00); + reg_w1(gspca_dev, 0x01, sn9c1xx[0]); /*fixme:jfm was [1] en v1*/ /* configure gpio */ reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2); reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2); - reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5); /* jfm was 3 */ + reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5); /* jfm len was 3 */ switch (sd->bridge) { case BRIDGE_SN9C325: reg9a = reg9a_sn9c325; @@ -685,35 +708,25 @@ static int configure_gpio(struct gspca_dev *gspca_dev, } reg_w(gspca_dev, 0x9a, reg9a, 6); - data = 0x60; /*fixme:jfm 60 00 00 (3) */ - reg_w(gspca_dev, 0xd4, &data, 1); + reg_w1(gspca_dev, 0xd4, 0x60); /*fixme:jfm 60 00 00 (3) ? */ reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f); switch (sd->bridge) { case BRIDGE_SN9C120: /* from win trace */ - data = 0x61; - reg_w(gspca_dev, 0x01, &data, 1); - data = 0x20; - reg_w(gspca_dev, 0x17, &data, 1); - data = 0x60; - reg_w(gspca_dev, 0x01, &data, 1); + reg_w1(gspca_dev, 0x01, 0x61); + reg_w1(gspca_dev, 0x17, 0x20); + reg_w1(gspca_dev, 0x01, 0x60); break; case BRIDGE_SN9C325: - data = 0x43; - reg_w(gspca_dev, 0x01, &data, 1); - data = 0xae; - reg_w(gspca_dev, 0x17, &data, 1); - data = 0x42; - reg_w(gspca_dev, 0x01, &data, 1); + reg_w1(gspca_dev, 0x01, 0x43); + reg_w1(gspca_dev, 0x17, 0xae); + reg_w1(gspca_dev, 0x01, 0x42); break; default: - data = 0x43; - reg_w(gspca_dev, 0x01, &data, 1); - data = 0x61; - reg_w(gspca_dev, 0x17, &data, 1); - data = 0x42; - reg_w(gspca_dev, 0x01, &data, 1); + reg_w1(gspca_dev, 0x01, 0x43); + reg_w1(gspca_dev, 0x17, 0x61); + reg_w1(gspca_dev, 0x01, 0x42); } if (sd->sensor == SENSOR_HV7131R) { @@ -770,6 +783,9 @@ static void ov7660_InitSensor(struct gspca_dev *gspca_dev) { int i = 0; + i2c_w8(gspca_dev, ov7660_sensor_init[i]); /* reset SCCB */ + i++; + msleep(20); while (ov7660_sensor_init[i][0]) { i2c_w8(gspca_dev, ov7660_sensor_init[i]); i++; @@ -782,13 +798,11 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - __u16 vendor; __u16 product; - vendor = id->idVendor; product = id->idProduct; sd->sensor = -1; - switch (vendor) { + switch (id->idVendor) { case 0x0458: /* Genius */ /* switch (product) { case 0x7025: */ @@ -960,7 +974,7 @@ static int sd_config(struct gspca_dev *gspca_dev, } if (sd->sensor < 0) { PDEBUG(D_ERR, "Invalid vendor/product %04x:%04x", - vendor, product); + id->idVendor, product); return -EINVAL; } @@ -983,34 +997,26 @@ static int sd_open(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; /* const __u8 *sn9c1xx; */ - __u8 regF1; __u8 regGpio[] = { 0x29, 0x74 }; + __u8 regF1; /* setup a selector by bridge */ - regF1 = 0x01; - reg_w(gspca_dev, 0xf1, ®F1, 1); + reg_w1(gspca_dev, 0xf1, 0x01); reg_r(gspca_dev, 0x00, 1); /* -> regF1 = 0x00 */ - regF1 = gspca_dev->usb_buf[0]; - reg_w(gspca_dev, 0xf1, ®F1, 1); + reg_w1(gspca_dev, 0xf1, gspca_dev->usb_buf[0]); reg_r(gspca_dev, 0x00, 1); regF1 = gspca_dev->usb_buf[0]; switch (sd->bridge) { case BRIDGE_SN9C102P: if (regF1 != 0x11) return -ENODEV; - reg_w(gspca_dev, 0x02, ®Gpio[1], 1); + reg_w1(gspca_dev, 0x02, regGpio[1]); break; case BRIDGE_SN9C105: if (regF1 != 0x11) return -ENODEV; reg_w(gspca_dev, 0x02, regGpio, 2); break; - case BRIDGE_SN9C110: - if (regF1 != 0x12) - return -ENODEV; - regGpio[1] = 0x62; - reg_w(gspca_dev, 0x02, ®Gpio[1], 1); - break; case BRIDGE_SN9C120: if (regF1 != 0x12) return -ENODEV; @@ -1018,16 +1024,15 @@ static int sd_open(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x02, regGpio, 2); break; default: +/* case BRIDGE_SN9C110: */ /* case BRIDGE_SN9C325: */ if (regF1 != 0x12) return -ENODEV; - regGpio[1] = 0x62; - reg_w(gspca_dev, 0x02, ®Gpio[1], 1); + reg_w1(gspca_dev, 0x02, 0x62); break; } - regF1 = 0x01; - reg_w(gspca_dev, 0xf1, ®F1, 1); + reg_w1(gspca_dev, 0xf1, 0x01); return 0; } @@ -1123,7 +1128,7 @@ static void setbrightness(struct gspca_dev *gspca_dev) } k2 = sd->brightness >> 10; - reg_w(gspca_dev, 0x96, &k2, 1); + reg_w1(gspca_dev, 0x96, k2); } static void setcontrast(struct gspca_dev *gspca_dev) @@ -1152,7 +1157,7 @@ static void setcolors(struct gspca_dev *gspca_dev) data = (colour + 32) & 0x7f; /* blue */ else data = (-colour + 32) & 0x7f; /* red */ - reg_w(gspca_dev, 0x05, &data, 1); + reg_w1(gspca_dev, 0x05, data); } /* -- start the camera -- */ @@ -1165,7 +1170,6 @@ static void sd_start(struct gspca_dev *gspca_dev) __u8 reg17; const __u8 *sn9c1xx; int mode; - static const __u8 DC29[] = { 0x6a, 0x50, 0x00, 0x00, 0x50, 0x3c }; static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f }; static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec }; static const __u8 CA_sn9c120[] = @@ -1179,21 +1183,20 @@ static void sd_start(struct gspca_dev *gspca_dev) /*fixme:jfm this sequence should appear at end of sd_start */ /* with - data = 0x44; - reg_w(gspca_dev, 0x01, &data, 1); */ - reg_w(gspca_dev, 0x15, &sn9c1xx[0x15], 1); - reg_w(gspca_dev, 0x16, &sn9c1xx[0x16], 1); - reg_w(gspca_dev, 0x12, &sn9c1xx[0x12], 1); - reg_w(gspca_dev, 0x13, &sn9c1xx[0x13], 1); - reg_w(gspca_dev, 0x18, &sn9c1xx[0x18], 1); - reg_w(gspca_dev, 0xd2, &DC29[0], 1); - reg_w(gspca_dev, 0xd3, &DC29[1], 1); - reg_w(gspca_dev, 0xc6, &DC29[2], 1); - reg_w(gspca_dev, 0xc7, &DC29[3], 1); - reg_w(gspca_dev, 0xc8, &DC29[4], 1); - reg_w(gspca_dev, 0xc9, &DC29[5], 1); + reg_w1(gspca_dev, 0x01, 0x44); */ + reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]); + reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]); + reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]); + reg_w1(gspca_dev, 0x13, sn9c1xx[0x13]); + reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]); + reg_w1(gspca_dev, 0xd2, 0x6a); /* DC29 */ + reg_w1(gspca_dev, 0xd3, 0x50); + reg_w1(gspca_dev, 0xc6, 0x00); + reg_w1(gspca_dev, 0xc7, 0x00); + reg_w1(gspca_dev, 0xc8, 0x50); + reg_w1(gspca_dev, 0xc9, 0x3c); /*fixme:jfm end of ending sequence */ - reg_w(gspca_dev, 0x18, &sn9c1xx[0x18], 1); + reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]); switch (sd->bridge) { case BRIDGE_SN9C325: data = 0xae; @@ -1205,11 +1208,11 @@ static void sd_start(struct gspca_dev *gspca_dev) data = 0x60; break; } - reg_w(gspca_dev, 0x17, &data, 1); - reg_w(gspca_dev, 0x05, &sn9c1xx[5], 1); - reg_w(gspca_dev, 0x07, &sn9c1xx[7], 1); - reg_w(gspca_dev, 0x06, &sn9c1xx[6], 1); - reg_w(gspca_dev, 0x14, &sn9c1xx[0x14], 1); + reg_w1(gspca_dev, 0x17, data); + reg_w1(gspca_dev, 0x05, sn9c1xx[5]); + reg_w1(gspca_dev, 0x07, sn9c1xx[7]); + reg_w1(gspca_dev, 0x06, sn9c1xx[6]); + reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]); switch (sd->bridge) { case BRIDGE_SN9C325: reg_w(gspca_dev, 0x20, regsn20_sn9c325, @@ -1217,10 +1220,8 @@ static void sd_start(struct gspca_dev *gspca_dev) for (i = 0; i < 8; i++) reg_w(gspca_dev, 0x84, reg84_sn9c325, sizeof reg84_sn9c325); - data = 0x0a; - reg_w(gspca_dev, 0x9a, &data, 1); - data = 0x60; - reg_w(gspca_dev, 0x99, &data, 1); + reg_w1(gspca_dev, 0x9a, 0x0a); + reg_w1(gspca_dev, 0x99, 0x60); break; case BRIDGE_SN9C120: reg_w(gspca_dev, 0x20, regsn20_sn9c120, @@ -1233,39 +1234,30 @@ static void sd_start(struct gspca_dev *gspca_dev) sizeof reg84_sn9c120_2); reg_w(gspca_dev, 0x84, reg84_sn9c120_3, sizeof reg84_sn9c120_3); - data = 0x05; - reg_w(gspca_dev, 0x9a, &data, 1); - data = 0x5b; - reg_w(gspca_dev, 0x99, &data, 1); + reg_w1(gspca_dev, 0x9a, 0x05); + reg_w1(gspca_dev, 0x99, 0x5b); break; default: reg_w(gspca_dev, 0x20, regsn20, sizeof regsn20); for (i = 0; i < 8; i++) reg_w(gspca_dev, 0x84, reg84, sizeof reg84); - data = 0x08; - reg_w(gspca_dev, 0x9a, &data, 1); - data = 0x59; - reg_w(gspca_dev, 0x99, &data, 1); + reg_w1(gspca_dev, 0x9a, 0x08); + reg_w1(gspca_dev, 0x99, 0x59); break; } mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; - reg1 = 0x02; + if (mode) + reg1 = 0x46; /* 320 clk 48Mhz */ + else + reg1 = 0x06; /* 640 clk 24Mz */ reg17 = 0x61; switch (sd->sensor) { case SENSOR_HV7131R: hv7131R_InitSensor(gspca_dev); - if (mode) - reg1 = 0x46; /* 320 clk 48Mhz */ - else - reg1 = 0x06; /* 640 clk 24Mz */ break; case SENSOR_MI0360: mi0360_InitSensor(gspca_dev); - if (mode) - reg1 = 0x46; /* 320 clk 48Mhz */ - else - reg1 = 0x06; /* 640 clk 24Mz */ break; case SENSOR_MO4000: mo4000_InitSensor(gspca_dev); @@ -1274,13 +1266,13 @@ static void sd_start(struct gspca_dev *gspca_dev) reg1 = 0x06; /* clk 24Mz */ } else { reg17 = 0x22; /* 640 MCKSIZE */ - reg1 = 0x06; /* 640 clk 24Mz */ +/* reg1 = 0x06; * 640 clk 24Mz (done) */ } break; case SENSOR_OV7648: + ov7648_InitSensor(gspca_dev); reg17 = 0xa2; reg1 = 0x44; - ov7648_InitSensor(gspca_dev); /* if (mode) ; * 320x2... else @@ -1292,7 +1284,7 @@ static void sd_start(struct gspca_dev *gspca_dev) if (mode) { /* reg17 = 0x21; * 320 */ /* reg1 = 0x44; */ - reg1 = 0x46; +/* reg1 = 0x46; (done) */ } else { reg17 = 0xa2; /* 640 */ reg1 = 0x40; @@ -1321,16 +1313,16 @@ static void sd_start(struct gspca_dev *gspca_dev) /* here change size mode 0 -> VGA; 1 -> CIF */ data = 0x40 | sn9c1xx[0x18] | (mode << 4); - reg_w(gspca_dev, 0x18, &data, 1); + reg_w1(gspca_dev, 0x18, data); reg_w(gspca_dev, 0x100, qtable4, 0x40); reg_w(gspca_dev, 0x140, qtable4 + 0x40, 0x40); data = sn9c1xx[0x18] | (mode << 4); - reg_w(gspca_dev, 0x18, &data, 1); + reg_w1(gspca_dev, 0x18, data); - reg_w(gspca_dev, 0x17, ®17, 1); - reg_w(gspca_dev, 0x01, ®1, 1); + reg_w1(gspca_dev, 0x17, reg17); + reg_w1(gspca_dev, 0x01, reg1); setbrightness(gspca_dev); setcontrast(gspca_dev); } @@ -1342,7 +1334,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) { 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 }; static const __u8 stopmi0360[] = { 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 }; - __u8 regF1; __u8 data; const __u8 *sn9c1xx; @@ -1366,12 +1357,11 @@ static void sd_stopN(struct gspca_dev *gspca_dev) break; } sn9c1xx = sn_tb[(int) sd->sensor]; - reg_w(gspca_dev, 0x01, &sn9c1xx[1], 1); - reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 1); - reg_w(gspca_dev, 0x01, &sn9c1xx[1], 1); - reg_w(gspca_dev, 0x01, &data, 1); - regF1 = 0x01; - reg_w(gspca_dev, 0xf1, ®F1, 1); + reg_w1(gspca_dev, 0x01, sn9c1xx[1]); + reg_w1(gspca_dev, 0x17, sn9c1xx[0x17]); + reg_w1(gspca_dev, 0x01, sn9c1xx[1]); + reg_w1(gspca_dev, 0x01, data); + reg_w1(gspca_dev, 0xf1, 0x01); } static void sd_stop0(struct gspca_dev *gspca_dev) -- cgit v1.2.3 From bb64e86c3ad55e70a8001d87c050fd3a82004d17 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Sat, 19 Jul 2008 06:49:28 -0300 Subject: V4L/DVB (8436): gspca: Version number only in the main driver. The version numbers of the subrivers will be removed as these ones will be changed for any other purpose. Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 8170a6937b8..8e8d3c6121b 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -43,8 +43,7 @@ MODULE_AUTHOR("Jean-Francois Moine "); MODULE_DESCRIPTION("GSPCA USB Camera Driver"); MODULE_LICENSE("GPL"); -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 2, 0) static int video_nr = -1; @@ -1886,7 +1885,10 @@ EXPORT_SYMBOL(gspca_auto_gain_n_exposure); /* -- module insert / remove -- */ static int __init gspca_init(void) { - info("main v%s registered", version); + info("main v%d.%d.%d registered", + (DRIVER_VERSION_NUMBER >> 16) & 0xff, + (DRIVER_VERSION_NUMBER >> 8) & 0xff, + DRIVER_VERSION_NUMBER & 0xff); return 0; } static void __exit gspca_exit(void) -- cgit v1.2.3 From 63fc4a038d8ca5e2da8c14c01b16876685beacf4 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Mon, 21 Jul 2008 05:42:17 -0300 Subject: V4L/DVB (8438): gspca: Lack of matrix for zc3xx - tas5130c (vf0250). Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/zc3xx.c | 362 +++++++++++++++++++------------------- 1 file changed, 185 insertions(+), 177 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index b761b11c5c6..f8d6f1780a4 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -24,9 +24,6 @@ #include "gspca.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; - MODULE_AUTHOR("Michel Xhaard , " "Serge A. Suchkov "); MODULE_DESCRIPTION("GSPCA ZC03xx/VC3xx USB Camera Driver"); @@ -49,7 +46,7 @@ struct sd { __u8 sharpness; char qindex; - char sensor; /* Type of image sensor chip */ + signed char sensor; /* Type of image sensor chip */ /* !! values used in different tables */ #define SENSOR_CS2102 0 #define SENSOR_CS2102K 1 @@ -2205,10 +2202,10 @@ static const struct usb_action hdcs2020xb_InitialScale[] = { }; static const struct usb_action hdcs2020b_50HZ[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x13, 0x0018}, /* 00,13,18,aa */ - {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ - {0xaa, 0x0e, 0x0005}, /* 00,0e,05,aa */ - {0xaa, 0x19, 0x001f}, /* 00,19,1f,aa */ + {0xaa, 0x13, 0x0018}, /* 00,13,18,aa */ + {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ + {0xaa, 0x0e, 0x0005}, /* 00,0e,05,aa */ + {0xaa, 0x19, 0x001f}, /* 00,19,1f,aa */ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */ {0xa0, 0x76, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,76,cc */ @@ -2226,10 +2223,10 @@ static const struct usb_action hdcs2020b_50HZ[] = { }; static const struct usb_action hdcs2020b_60HZ[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x13, 0x0031}, /* 00,13,31,aa */ - {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ - {0xaa, 0x0e, 0x0004}, /* 00,0e,04,aa */ - {0xaa, 0x19, 0x00cd}, /* 00,19,cd,aa */ + {0xaa, 0x13, 0x0031}, /* 00,13,31,aa */ + {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ + {0xaa, 0x0e, 0x0004}, /* 00,0e,04,aa */ + {0xaa, 0x19, 0x00cd}, /* 00,19,cd,aa */ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */ {0xa0, 0x62, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,62,cc */ @@ -2247,10 +2244,10 @@ static const struct usb_action hdcs2020b_60HZ[] = { }; static const struct usb_action hdcs2020b_NoFliker[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ - {0xaa, 0x13, 0x0010}, /* 00,13,10,aa */ - {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ - {0xaa, 0x0e, 0x0004}, /* 00,0e,04,aa */ - {0xaa, 0x19, 0x0000}, /* 00,19,00,aa */ + {0xaa, 0x13, 0x0010}, /* 00,13,10,aa */ + {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ + {0xaa, 0x0e, 0x0004}, /* 00,0e,04,aa */ + {0xaa, 0x19, 0x0000}, /* 00,19,00,aa */ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,02,cc */ {0xa0, 0x70, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,70,cc */ @@ -4102,27 +4099,27 @@ static const struct usb_action pas106b_Initial_com[] = { static const struct usb_action pas106b_Initial[] = { /* 176x144 */ /* JPEG control */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* Sream and Sensor specific */ - {0xa0, 0x0f, ZC3XX_R010_CMOSSENSORSELECT}, /* CMOSSensorSelect */ + {0xa0, 0x0f, ZC3XX_R010_CMOSSENSORSELECT}, /* Picture size */ - {0xa0, 0x00, ZC3XX_R003_FRAMEWIDTHHIGH}, /* FrameWidthHigh 00 */ - {0xa0, 0xb0, ZC3XX_R004_FRAMEWIDTHLOW}, /* FrameWidthLow B0 */ - {0xa0, 0x00, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* FrameHeightHigh 00 */ - {0xa0, 0x90, ZC3XX_R006_FRAMEHEIGHTLOW}, /* FrameHightLow 90 */ + {0xa0, 0x00, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0xb0, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x00, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0x90, ZC3XX_R006_FRAMEHEIGHTLOW}, /* System */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* SystemOperating */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* Sream and Sensor specific */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* VideoControlFunction */ - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* VideoControlFunction */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* Sensor Interface */ - {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* Compatibily Mode */ + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* Window inside sensor array */ - {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, /* WinXStartLow */ - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* FirstYLow */ - {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, /* FirstxLow */ - {0xa0, 0x28, ZC3XX_R09C_WINHEIGHTLOW}, /* WinHeightLow */ - {0xa0, 0x68, ZC3XX_R09E_WINWIDTHLOW}, /* WinWidthLow */ + {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0x28, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x68, ZC3XX_R09E_WINWIDTHLOW}, /* Init the sensor */ {0xaa, 0x02, 0x0004}, {0xaa, 0x08, 0x0000}, @@ -4135,40 +4132,40 @@ static const struct usb_action pas106b_Initial[] = { /* 176x144 */ {0xaa, 0x14, 0x0081}, /* Other registors */ - {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* SensorCorrection */ + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* Frame retreiving */ - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* AutoAdjustFPS */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* Gains */ - {0xa0, 0xa0, ZC3XX_R1A8_DIGITALGAIN}, /* DigitalGain */ + {0xa0, 0xa0, ZC3XX_R1A8_DIGITALGAIN}, /* Unknown */ {0xa0, 0x00, 0x01ad}, /* Sharpness */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* SharpnessMode */ - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* Sharpness05 */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* Other registors */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* OperationMode */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* Auto exposure and white balance */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* AWBStatus */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /*Dead pixels */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* DeadPixelsMode */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* EEPROM */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* EEPROMAccess */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* JPEG control */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */ - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* Other registers */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* OperationMode */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* Auto exposure and white balance */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* AWBStatus */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /*Dead pixels */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* DeadPixelsMode */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* EEPROM */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* EEPROMAccess */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* JPEG control */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */ - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */ {0xa0, 0xf4, ZC3XX_R10B_RGB01}, @@ -4180,67 +4177,67 @@ static const struct usb_action pas106b_Initial[] = { /* 176x144 */ {0xa0, 0xf4, ZC3XX_R111_RGB21}, {0xa0, 0x58, ZC3XX_R112_RGB22}, /* Auto correction */ - {0xa0, 0x03, ZC3XX_R181_WINXSTART}, /* WinXstart */ - {0xa0, 0x08, ZC3XX_R182_WINXWIDTH}, /* WinXWidth */ - {0xa0, 0x16, ZC3XX_R183_WINXCENTER}, /* WinXCenter */ - {0xa0, 0x03, ZC3XX_R184_WINYSTART}, /* WinYStart */ - {0xa0, 0x05, ZC3XX_R185_WINYWIDTH}, /* WinYWidth */ - {0xa0, 0x14, ZC3XX_R186_WINYCENTER}, /* WinYCenter */ - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */ + {0xa0, 0x03, ZC3XX_R181_WINXSTART}, + {0xa0, 0x08, ZC3XX_R182_WINXWIDTH}, + {0xa0, 0x16, ZC3XX_R183_WINXCENTER}, + {0xa0, 0x03, ZC3XX_R184_WINYSTART}, + {0xa0, 0x05, ZC3XX_R185_WINYWIDTH}, + {0xa0, 0x14, ZC3XX_R186_WINYCENTER}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, /* Auto exposure and white balance */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* ExposureLimitHigh */ - {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* ExposureLimitMid */ - {0xa0, 0xb1, ZC3XX_R192_EXPOSURELIMITLOW}, /* ExposureLimitLow */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* AntiFlickerHigh */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* AntiFlickerLow */ - {0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW}, /* AntiFlickerLow */ - {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* AEBFreeze */ - {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* AEBUnfreeze */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xb1, ZC3XX_R192_EXPOSURELIMITLOW}, + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW}, + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* sensor on */ {0xaa, 0x07, 0x00b1}, {0xaa, 0x05, 0x0003}, {0xaa, 0x04, 0x0001}, {0xaa, 0x03, 0x003b}, /* Gains */ - {0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* DigitalLimitDiff */ - {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* DigitalGainStep */ - {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN}, /* GlobalGain */ - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* GlobalGain */ + {0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* Auto correction */ - {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */ + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, {0xa1, 0x01, 0x0180}, /* AutoCorrectEnable */ - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* Gains */ - {0xa0, 0x40, ZC3XX_R116_RGAIN}, /* RGain */ - {0xa0, 0x40, ZC3XX_R117_GGAIN}, /* GGain */ - {0xa0, 0x40, ZC3XX_R118_BGAIN}, /* BGain */ + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, {} }; static const struct usb_action pas106b_InitialScale[] = { /* 352x288 */ /* JPEG control */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* Sream and Sensor specific */ - {0xa0, 0x0f, ZC3XX_R010_CMOSSENSORSELECT}, /* CMOSSensorSelect */ + {0xa0, 0x0f, ZC3XX_R010_CMOSSENSORSELECT}, /* Picture size */ - {0xa0, 0x01, ZC3XX_R003_FRAMEWIDTHHIGH}, /* FrameWidthHigh */ - {0xa0, 0x60, ZC3XX_R004_FRAMEWIDTHLOW}, /* FrameWidthLow */ - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* FrameHeightHigh */ - {0xa0, 0x20, ZC3XX_R006_FRAMEHEIGHTLOW}, /* FrameHightLow */ + {0xa0, 0x01, ZC3XX_R003_FRAMEWIDTHHIGH}, + {0xa0, 0x60, ZC3XX_R004_FRAMEWIDTHLOW}, + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, + {0xa0, 0x20, ZC3XX_R006_FRAMEHEIGHTLOW}, /* System */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* SystemOperating */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* Sream and Sensor specific */ - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* VideoControlFunction */ - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* VideoControlFunction */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* Sensor Interface */ - {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* Compatibily Mode */ + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* Window inside sensor array */ - {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, /* WinXStartLow */ - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* FirstYLow */ - {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, /* FirstxLow */ - {0xa0, 0x28, ZC3XX_R09C_WINHEIGHTLOW}, /* WinHeightLow */ - {0xa0, 0x68, ZC3XX_R09E_WINWIDTHLOW}, /* WinWidthLow */ + {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, + {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, + {0xa0, 0x28, ZC3XX_R09C_WINHEIGHTLOW}, + {0xa0, 0x68, ZC3XX_R09E_WINWIDTHLOW}, /* Init the sensor */ {0xaa, 0x02, 0x0004}, {0xaa, 0x08, 0x0000}, @@ -4253,41 +4250,41 @@ static const struct usb_action pas106b_InitialScale[] = { /* 352x288 */ {0xaa, 0x14, 0x0081}, /* Other registors */ - {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* SensorCorrection */ + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* Frame retreiving */ - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* AutoAdjustFPS */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* Gains */ - {0xa0, 0xa0, ZC3XX_R1A8_DIGITALGAIN}, /* DigitalGain */ + {0xa0, 0xa0, ZC3XX_R1A8_DIGITALGAIN}, /* Unknown */ {0xa0, 0x00, 0x01ad}, /* Sharpness */ - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* SharpnessMode */ - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* Sharpness05 */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* Other registors */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* OperationMode */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* Auto exposure and white balance */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* AWBStatus */ - {0xa0, 0x80, ZC3XX_R18D_YTARGET}, /* ????????? */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, + {0xa0, 0x80, ZC3XX_R18D_YTARGET}, /*Dead pixels */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* DeadPixelsMode */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* EEPROM */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* EEPROMAccess */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* JPEG control */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */ - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* Other registers */ - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* OperationMode */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* Auto exposure and white balance */ - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* AWBStatus */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /*Dead pixels */ - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* DeadPixelsMode */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* EEPROM */ - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* EEPROMAccess */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* JPEG control */ - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* ClockSetting */ - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, + {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, {0xa0, 0x58, ZC3XX_R10A_RGB00}, /* matrix */ {0xa0, 0xf4, ZC3XX_R10B_RGB01}, @@ -4299,43 +4296,43 @@ static const struct usb_action pas106b_InitialScale[] = { /* 352x288 */ {0xa0, 0xf4, ZC3XX_R111_RGB21}, {0xa0, 0x58, ZC3XX_R112_RGB22}, /* Auto correction */ - {0xa0, 0x03, ZC3XX_R181_WINXSTART}, /* WinXstart */ - {0xa0, 0x08, ZC3XX_R182_WINXWIDTH}, /* WinXWidth */ - {0xa0, 0x16, ZC3XX_R183_WINXCENTER}, /* WinXCenter */ - {0xa0, 0x03, ZC3XX_R184_WINYSTART}, /* WinYStart */ - {0xa0, 0x05, ZC3XX_R185_WINYWIDTH}, /* WinYWidth */ - {0xa0, 0x14, ZC3XX_R186_WINYCENTER}, /* WinYCenter */ - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */ + {0xa0, 0x03, ZC3XX_R181_WINXSTART}, + {0xa0, 0x08, ZC3XX_R182_WINXWIDTH}, + {0xa0, 0x16, ZC3XX_R183_WINXCENTER}, + {0xa0, 0x03, ZC3XX_R184_WINYSTART}, + {0xa0, 0x05, ZC3XX_R185_WINYWIDTH}, + {0xa0, 0x14, ZC3XX_R186_WINYCENTER}, + {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, /* Auto exposure and white balance */ - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* ExposureLimitHigh 0 */ - {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, /* ExposureLimitMid */ - {0xa0, 0xb1, ZC3XX_R192_EXPOSURELIMITLOW}, /* ExposureLimitLow 0xb1 */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, + {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0xb1, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* AntiFlickerHigh 0x00 */ - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* AntiFlickerLow 0x00 */ - {0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW}, /* AntiFlickerLow 0x87 */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, + {0xa0, 0x87, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* AEBFreeze 0x10 0x0c */ - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* AEBUnfreeze 0x30 0x18 */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* sensor on */ {0xaa, 0x07, 0x00b1}, {0xaa, 0x05, 0x0003}, {0xaa, 0x04, 0x0001}, {0xaa, 0x03, 0x003b}, /* Gains */ - {0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* DigitalLimitDiff */ - {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, /* DigitalGainStep */ - {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN}, /* GlobalGain */ - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* GlobalGain */ + {0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF}, + {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, + {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN}, + {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, /* Auto correction */ - {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */ + {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, {0xa1, 0x01, 0x0180}, /* AutoCorrectEnable */ - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* AutoCorrectEnable */ + {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* Gains */ - {0xa0, 0x40, ZC3XX_R116_RGAIN}, /* RGain */ - {0xa0, 0x40, ZC3XX_R117_GGAIN}, /* GGain */ - {0xa0, 0x40, ZC3XX_R118_BGAIN}, /* BGain */ + {0xa0, 0x40, ZC3XX_R116_RGAIN}, + {0xa0, 0x40, ZC3XX_R117_GGAIN}, + {0xa0, 0x40, ZC3XX_R118_BGAIN}, {0xa0, 0x00, 0x0007}, /* AutoCorrectEnable */ {0xa0, 0xff, ZC3XX_R018_FRAMELOST}, /* Frame adjust */ @@ -4459,8 +4456,8 @@ static const struct usb_action pb03303x_Initial[] = { {0xa0, 0x50, ZC3XX_R112_RGB22}, {0xa1, 0x01, 0x0008}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ + {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, {0xa1, 0x01, 0x01c8}, {0xa1, 0x01, 0x01c9}, {0xa1, 0x01, 0x01ca}, @@ -5984,7 +5981,7 @@ static const struct usb_action tas5130c_vf0250_Initial[] = { {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */ {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */ {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ - {0xaa, 0x01, 0x0000}, +/*?? {0xaa, 0x01, 0x0000}, */ {0xaa, 0x01, 0x0000}, {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */ {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */ @@ -6000,8 +5997,8 @@ static const struct usb_action tas5130c_vf0250_Initial[] = { {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */ {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */ - {0xa0, 0x00, 0x0039}, - {0xa1, 0x01, 0x0037}, +/*?? {0xa0, 0x00, 0x0039}, + {0xa1, 0x01, 0x0037}, */ {0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */ {0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa, (e6 -> e8) */ {0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */ @@ -6272,7 +6269,7 @@ static void reg_w(struct usb_device *dev, __u8 value, __u16 index) { - PDEBUG(D_USBO, "reg w %02x -> [%04x]", value, index); + PDEBUG(D_USBO, "reg w [%04x] = %02x", index, value); reg_w_i(dev, value, index); } @@ -6280,17 +6277,17 @@ static __u16 i2c_read(struct gspca_dev *gspca_dev, __u8 reg) { __u8 retbyte; - __u8 retval[2]; + __u16 retval; reg_w_i(gspca_dev->dev, reg, 0x92); reg_w_i(gspca_dev->dev, 0x02, 0x90); /* <- read command */ msleep(25); retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ - retval[0] = reg_r_i(gspca_dev, 0x0095); /* read Lowbyte */ - retval[1] = reg_r_i(gspca_dev, 0x0096); /* read Hightbyte */ - PDEBUG(D_USBO, "i2c r [%02x] -> (%02x) %02x%02x", - reg, retbyte, retval[1], retval[0]); - return (retval[1] << 8) | retval[0]; + retval = reg_r_i(gspca_dev, 0x0095); /* read Lowbyte */ + retval |= reg_r_i(gspca_dev, 0x0096) << 8; /* read Hightbyte */ + PDEBUG(D_USBO, "i2c r [%02x] -> %04x (%02x)", + reg, retval, retbyte); + return retval; } static __u8 i2c_write(struct gspca_dev *gspca_dev, @@ -6306,7 +6303,7 @@ static __u8 i2c_write(struct gspca_dev *gspca_dev, reg_w_i(gspca_dev->dev, 0x01, 0x90); /* <- write command */ msleep(5); retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ - PDEBUG(D_USBO, "i2c w [%02x] %02x%02x (%02x)", + PDEBUG(D_USBO, "i2c w [%02x] = %02x%02x (%02x)", reg, valH, valL, retbyte); return retbyte; } @@ -6349,6 +6346,8 @@ static void setmatrix(struct gspca_dev *gspca_dev) {0x58, 0xf4, 0xf4, 0xf4, 0x58, 0xf4, 0xf4, 0xf4, 0x58}; static const __u8 po2030_matrix[9] = {0x60, 0xf0, 0xf0, 0xf0, 0x60, 0xf0, 0xf0, 0xf0, 0x60}; + static const __u8 vf0250_matrix[9] = + {0x7b, 0xea, 0xea, 0xea, 0x7b, 0xea, 0xea, 0xea, 0x7b}; switch (sd->sensor) { case SENSOR_GC0305: @@ -6363,8 +6362,9 @@ static void setmatrix(struct gspca_dev *gspca_dev) case SENSOR_PO2030: matrix = po2030_matrix; break; - case SENSOR_TAS5130C_VF0250: /* no matrix? */ - return; + case SENSOR_TAS5130C_VF0250: + matrix = vf0250_matrix; + break; default: /* matrix already loaded */ return; } @@ -6744,7 +6744,7 @@ static int vga_2wr_probe(struct gspca_dev *gspca_dev) return 0x04; /* CS2102 */ start_2wr_probe(dev, 0x06); /* OmniVision */ - reg_w(dev, 0x08, 0x8d); + reg_w(dev, 0x08, 0x008d); i2c_write(gspca_dev, 0x11, 0xaa, 0x00); retbyte = i2c_read(gspca_dev, 0x11); if (retbyte != 0) { @@ -6778,7 +6778,7 @@ static int vga_2wr_probe(struct gspca_dev *gspca_dev) return 0x0c; /* ICM105A */ start_2wr_probe(dev, 0x0e); /* PAS202BCB */ - reg_w(dev, 0x08, 0x8d); + reg_w(dev, 0x08, 0x008d); i2c_write(gspca_dev, 0x03, 0xaa, 0x00); msleep(500); retbyte = i2c_read(gspca_dev, 0x03); @@ -6830,7 +6830,6 @@ static const struct sensor_by_chipset_revision chipset_revision_sensor[] = { {0x8001, 0x13}, {0x8000, 0x14}, /* CS2102K */ {0x8400, 0x15}, /* TAS5130K */ - {0, 0} }; static int vga_3wr_probe(struct gspca_dev *gspca_dev) @@ -6843,7 +6842,7 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) /*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/ reg_w(dev, 0x02, 0x0010); - reg_r(gspca_dev, 0x10); + reg_r(gspca_dev, 0x0010); reg_w(dev, 0x01, 0x0000); reg_w(dev, 0x00, 0x0010); reg_w(dev, 0x01, 0x0001); @@ -6869,17 +6868,15 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) PDEBUG(D_PROBE, "probe 3wr vga 1 0x%04x", checkword); reg_r(gspca_dev, 0x0010); /* this is tested only once anyway */ - i = 0; - while (chipset_revision_sensor[i].revision) { + for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) { if (chipset_revision_sensor[i].revision == checkword) { sd->chip_revision = checkword; send_unknown(dev, SENSOR_PB0330); return chipset_revision_sensor[i].internal_sensor_id; } - i++; } - reg_w(dev, 0x01, 0x0000); + reg_w(dev, 0x01, 0x0000); /* check ?? */ reg_w(dev, 0x01, 0x0001); reg_w(dev, 0xdd, 0x008b); reg_w(dev, 0x0a, 0x0010); @@ -6901,8 +6898,11 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) retbyte = i2c_read(gspca_dev, 0x00); if (retbyte != 0) { PDEBUG(D_PROBE, "probe 3wr vga type %02x", retbyte); - send_unknown(dev, SENSOR_GC0305); - return retbyte; /* 0x29 = gc0305 - should continue? */ + if (retbyte == 0x11) /* VF0250 */ + return 0x0250; + if (retbyte == 0x29) /* gc0305 */ + send_unknown(dev, SENSOR_GC0305); + return retbyte; } reg_w(dev, 0x01, 0x0000); /* check OmniVision */ @@ -6918,18 +6918,18 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) return 0x06; /* OmniVision confirm ? */ } - reg_w(dev, 0x01, 0x00); - reg_w(dev, 0x00, 0x02); - reg_w(dev, 0x01, 0x10); - reg_w(dev, 0x01, 0x01); - reg_w(dev, 0xee, 0x8b); - reg_w(dev, 0x03, 0x12); + reg_w(dev, 0x01, 0x0000); + reg_w(dev, 0x00, 0x0002); + reg_w(dev, 0x01, 0x0010); + reg_w(dev, 0x01, 0x0001); + reg_w(dev, 0xee, 0x008b); + reg_w(dev, 0x03, 0x0012); /* msleep(150); */ - reg_w(dev, 0x01, 0x12); - reg_w(dev, 0x05, 0x12); - retbyte = i2c_read(gspca_dev, 0x00); /* ID 0 */ + reg_w(dev, 0x01, 0x0012); + reg_w(dev, 0x05, 0x0012); + retbyte = i2c_read(gspca_dev, 0x0000); /* ID 0 */ checkword = retbyte << 8; - retbyte = i2c_read(gspca_dev, 0x01); /* ID 1 */ + retbyte = i2c_read(gspca_dev, 0x0001); /* ID 1 */ checkword |= retbyte; PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", checkword); if (checkword == 0x2030) { @@ -6939,14 +6939,14 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) return checkword; } - reg_w(dev, 0x01, 0x00); - reg_w(dev, 0x0a, 0x10); - reg_w(dev, 0xd3, 0x8b); - reg_w(dev, 0x01, 0x01); - reg_w(dev, 0x03, 0x12); - reg_w(dev, 0x01, 0x12); - reg_w(dev, 0x05, 0x01); - reg_w(dev, 0xd3, 0x8b); + reg_w(dev, 0x01, 0x0000); + reg_w(dev, 0x0a, 0x0010); + reg_w(dev, 0xd3, 0x008b); + reg_w(dev, 0x01, 0x0001); + reg_w(dev, 0x03, 0x0012); + reg_w(dev, 0x01, 0x0012); + reg_w(dev, 0x05, 0x0001); + reg_w(dev, 0xd3, 0x008b); retbyte = i2c_read(gspca_dev, 0x01); if (retbyte != 0) { PDEBUG(D_PROBE, "probe 3wr vga type 0a ?"); @@ -6962,7 +6962,9 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_MC501CB: + return -1; /* don't probe */ case SENSOR_TAS5130C_VF0250: + /* may probe but with write in reg 0x0010 */ return -1; /* don't probe */ } sensor = vga_2wr_probe(gspca_dev); @@ -7010,6 +7012,7 @@ static int sd_config(struct gspca_dev *gspca_dev, /* define some sensors from the vendor/product */ sd->sharpness = 2; + sd->sensor = -1; switch (id->idVendor) { case 0x041e: /* Creative */ switch (id->idProduct) { @@ -7119,6 +7122,10 @@ static int sd_config(struct gspca_dev *gspca_dev, PDEBUG(D_PROBE, "Find Sensor GC0305"); sd->sensor = SENSOR_GC0305; break; + case 0x0250: + PDEBUG(D_PROBE, "Sensor Tas5130 (VF0250)"); + sd->sensor = SENSOR_TAS5130C_VF0250; + break; case 0x2030: PDEBUG(D_PROBE, "Find Sensor PO2030"); sd->sensor = SENSOR_PO2030; @@ -7235,6 +7242,7 @@ static void sd_start(struct gspca_dev *gspca_dev) case SENSOR_GC0305: case SENSOR_OV7620: case SENSOR_PO2030: + case SENSOR_TAS5130C_VF0250: msleep(100); /* ?? */ reg_r(gspca_dev, 0x0002); /* --> 0x40 */ reg_w(dev, 0x09, 0x01ad); /* (from win traces) */ @@ -7605,7 +7613,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } -- cgit v1.2.3 From 903e10aa664473ce19c30c0f80ffd7bbbbd8fc33 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 22 Jul 2008 02:35:05 -0300 Subject: V4L/DVB (8440): gspca: Makes some needlessly global functions static. Signed-off-by: Adrian Bunk Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 2 +- drivers/media/video/gspca/pac207.c | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 8e8d3c6121b..f815340511e 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -399,7 +399,7 @@ static struct usb_host_endpoint *alt_isoc(struct usb_host_interface *alt, * This routine may be called many times when the bandwidth is too small * (the bandwidth is checked on urb submit). */ -struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev) +static struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev) { struct usb_interface *intf; struct usb_host_endpoint *ep; diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c index fa7abc41109..f790746370d 100644 --- a/drivers/media/video/gspca/pac207.c +++ b/drivers/media/video/gspca/pac207.c @@ -27,9 +27,6 @@ #include "gspca.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; - MODULE_AUTHOR("Hans de Goede "); MODULE_DESCRIPTION("Pixart PAC207"); MODULE_LICENSE("GPL"); @@ -208,7 +205,7 @@ static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index, } -int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value) +static int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value) { struct usb_device *udev = gspca_dev->dev; int err; @@ -223,8 +220,7 @@ int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value) return err; } - -int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index) +static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index) { struct usb_device *udev = gspca_dev->dev; int res; @@ -609,7 +605,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } static void __exit sd_mod_exit(void) -- cgit v1.2.3 From 06ca78fa3a77c955bd46ba3dbe529c399d260aa4 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Tue, 22 Jul 2008 03:45:08 -0300 Subject: V4L/DVB (8441): gspca: Bad handling of start of frames in sonixj. Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index f815340511e..0f09784631a 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -209,6 +209,8 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev, &frame->v4l2_buf.timestamp); frame->v4l2_buf.sequence = ++gspca_dev->sequence; } else if (gspca_dev->last_packet_type == DISCARD_PACKET) { + if (packet_type == LAST_PACKET) + gspca_dev->last_packet_type = packet_type; return frame; } -- cgit v1.2.3 From 10b0e96ed9a1ce0412ef981cf6250f9de3c80b02 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Tue, 22 Jul 2008 05:35:10 -0300 Subject: V4L/DVB (8442): gspca: Remove the version from the subdrivers. Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/conex.c | 5 +---- drivers/media/video/gspca/etoms.c | 5 +---- drivers/media/video/gspca/mars.c | 5 +---- drivers/media/video/gspca/ov519.c | 5 +---- drivers/media/video/gspca/pac7311.c | 5 +---- drivers/media/video/gspca/sonixb.c | 5 +---- drivers/media/video/gspca/sonixj.c | 5 +---- drivers/media/video/gspca/spca500.c | 5 +---- drivers/media/video/gspca/spca501.c | 5 +---- drivers/media/video/gspca/spca505.c | 5 +---- drivers/media/video/gspca/spca506.c | 5 +---- drivers/media/video/gspca/spca508.c | 5 +---- drivers/media/video/gspca/spca561.c | 5 +---- drivers/media/video/gspca/stk014.c | 5 +---- drivers/media/video/gspca/sunplus.c | 5 +---- drivers/media/video/gspca/t613.c | 22 ++++++++++------------ drivers/media/video/gspca/tv8532.c | 5 +---- drivers/media/video/gspca/vc032x.c | 5 +---- 18 files changed, 27 insertions(+), 80 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c index 013d593b0c6..18c1dec2f76 100644 --- a/drivers/media/video/gspca/conex.c +++ b/drivers/media/video/gspca/conex.c @@ -25,9 +25,6 @@ #define CONEX_CAM 1 /* special JPEG header */ #include "jpeg.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; - MODULE_AUTHOR("Michel Xhaard "); MODULE_DESCRIPTION("GSPCA USB Conexant Camera Driver"); MODULE_LICENSE("GPL"); @@ -1038,7 +1035,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } static void __exit sd_mod_exit(void) diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c index 8ab4ea7201a..6f2f1d24b7e 100644 --- a/drivers/media/video/gspca/etoms.c +++ b/drivers/media/video/gspca/etoms.c @@ -22,9 +22,6 @@ #include "gspca.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; - MODULE_AUTHOR("Michel Xhaard "); MODULE_DESCRIPTION("Etoms USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -942,7 +939,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c index 88c2b02f380..a4706162f41 100644 --- a/drivers/media/video/gspca/mars.c +++ b/drivers/media/video/gspca/mars.c @@ -24,9 +24,6 @@ #include "gspca.h" #include "jpeg.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; - MODULE_AUTHOR("Michel Xhaard "); MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -451,7 +448,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } static void __exit sd_mod_exit(void) diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index 08d99c3b78e..f15bec7080c 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -24,9 +24,6 @@ #include "gspca.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; - MODULE_AUTHOR("Jean-Francois Moine "); MODULE_DESCRIPTION("OV519 USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -2169,7 +2166,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } static void __exit sd_mod_exit(void) diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c index 5c052e31be4..2267ae7cb87 100644 --- a/drivers/media/video/gspca/pac7311.c +++ b/drivers/media/video/gspca/pac7311.c @@ -23,9 +23,6 @@ #include "gspca.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; - MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); MODULE_DESCRIPTION("Pixart PAC7311"); MODULE_LICENSE("GPL"); @@ -747,7 +744,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } static void __exit sd_mod_exit(void) diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index dbeebe8625c..f6bef896d3a 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -24,9 +24,6 @@ #include "gspca.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 8) -static const char version[] = "2.1.8"; - MODULE_AUTHOR("Michel Xhaard "); MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -1464,7 +1461,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } static void __exit sd_mod_exit(void) diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index aa4d10b823e..35b1a3ee4c3 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -24,9 +24,6 @@ #include "gspca.h" #include "jpeg.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; - MODULE_AUTHOR("Michel Xhaard "); MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -1648,7 +1645,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - info("v%s registered", version); + info("registered"); return 0; } static void __exit sd_mod_exit(void) diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c index 15620611879..8c83823745f 100644 --- a/drivers/media/video/gspca/spca500.c +++ b/drivers/media/video/gspca/spca500.c @@ -24,9 +24,6 @@ #include "gspca.h" #include "jpeg.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; - MODULE_AUTHOR("Michel Xhaard "); MODULE_DESCRIPTION("GSPCA/SPCA500 USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -1203,7 +1200,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } static void __exit sd_mod_exit(void) diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c index 50e929de020..6537acee89d 100644 --- a/drivers/media/video/gspca/spca501.c +++ b/drivers/media/video/gspca/spca501.c @@ -23,9 +23,6 @@ #include "gspca.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; - MODULE_AUTHOR("Michel Xhaard "); MODULE_DESCRIPTION("GSPCA/SPCA501 USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -2216,7 +2213,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } static void __exit sd_mod_exit(void) diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c index ddea6e140aa..1bb23d03f04 100644 --- a/drivers/media/video/gspca/spca505.c +++ b/drivers/media/video/gspca/spca505.c @@ -23,9 +23,6 @@ #include "gspca.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; - MODULE_AUTHOR("Michel Xhaard "); MODULE_DESCRIPTION("GSPCA/SPCA505 USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -938,7 +935,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } static void __exit sd_mod_exit(void) diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c index 143203c1fd9..40e8541b2b8 100644 --- a/drivers/media/video/gspca/spca506.c +++ b/drivers/media/video/gspca/spca506.c @@ -25,9 +25,6 @@ #include "gspca.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; - MODULE_AUTHOR("Michel Xhaard "); MODULE_DESCRIPTION("GSPCA/SPCA506 USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -834,7 +831,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } static void __exit sd_mod_exit(void) diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c index d8cd93866a4..362f645d08c 100644 --- a/drivers/media/video/gspca/spca508.c +++ b/drivers/media/video/gspca/spca508.c @@ -22,9 +22,6 @@ #include "gspca.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; - MODULE_AUTHOR("Michel Xhaard "); MODULE_DESCRIPTION("GSPCA/SPCA508 USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -1778,7 +1775,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } static void __exit sd_mod_exit(void) diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c index b659bd0f788..85c37f396aa 100644 --- a/drivers/media/video/gspca/spca561.c +++ b/drivers/media/video/gspca/spca561.c @@ -24,9 +24,6 @@ #include "gspca.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; - MODULE_AUTHOR("Michel Xhaard "); MODULE_DESCRIPTION("GSPCA/SPCA561 USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -1039,7 +1036,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } static void __exit sd_mod_exit(void) diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c index c78ee0d3e59..90efde17b08 100644 --- a/drivers/media/video/gspca/stk014.c +++ b/drivers/media/video/gspca/stk014.c @@ -23,9 +23,6 @@ #include "gspca.h" #include "jpeg.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; - MODULE_AUTHOR("Jean-Francois Moine "); MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -576,7 +573,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - info("v%s registered", version); + info("registered"); return 0; } static void __exit sd_mod_exit(void) diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c index abd7bef9b3d..53e20275f26 100644 --- a/drivers/media/video/gspca/sunplus.c +++ b/drivers/media/video/gspca/sunplus.c @@ -24,9 +24,6 @@ #include "gspca.h" #include "jpeg.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 8) -static const char version[] = "2.1.8"; - MODULE_AUTHOR("Michel Xhaard "); MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -1664,7 +1661,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } static void __exit sd_mod_exit(void) diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c index 00f47e463a0..fc1c62e5a2f 100644 --- a/drivers/media/video/gspca/t613.c +++ b/drivers/media/video/gspca/t613.c @@ -1,12 +1,4 @@ /* - *Notes: * t613 + tas5130A - * * Focus to light do not balance well as in win. - * Quality in win is not good, but its kinda better. - * * Fix some "extraneous bytes", most of apps will show the image anyway - * * Gamma table, is there, but its really doing something? - * * 7~8 Fps, its ok, max on win its 10. - * Costantino Leandro - * * V4L2 by Jean-Francois Moine * * This program is free software; you can redistribute it and/or modify @@ -22,16 +14,22 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + *Notes: * t613 + tas5130A + * * Focus to light do not balance well as in win. + * Quality in win is not good, but its kinda better. + * * Fix some "extraneous bytes", most of apps will show the image anyway + * * Gamma table, is there, but its really doing something? + * * 7~8 Fps, its ok, max on win its 10. + * Costantino Leandro */ #define MODULE_NAME "t613" + #include "gspca.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; #define MAX_GAMMA 0x10 /* 0 to 15 */ -/* From LUVCVIEW */ #define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 3) MODULE_AUTHOR("Leandro Costantino "); @@ -1025,7 +1023,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } static void __exit sd_mod_exit(void) diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c index 0b793899095..cb2d9da2a22 100644 --- a/drivers/media/video/gspca/tv8532.c +++ b/drivers/media/video/gspca/tv8532.c @@ -22,9 +22,6 @@ #include "gspca.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; - MODULE_AUTHOR("Michel Xhaard "); MODULE_DESCRIPTION("TV8532 USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -656,7 +653,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c index fcf2c9e3257..e306ac42029 100644 --- a/drivers/media/video/gspca/vc032x.c +++ b/drivers/media/video/gspca/vc032x.c @@ -24,9 +24,6 @@ #include "gspca.h" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) -static const char version[] = "2.1.7"; - MODULE_AUTHOR("Michel Xhaard "); MODULE_DESCRIPTION("GSPCA/VC032X USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -1805,7 +1802,7 @@ static int __init sd_mod_init(void) { if (usb_register(&sd_driver) < 0) return -1; - PDEBUG(D_PROBE, "v%s registered", version); + PDEBUG(D_PROBE, "registered"); return 0; } static void __exit sd_mod_exit(void) -- cgit v1.2.3 From 72d18a7b9e1a3a9511bae78fc7f0932ae01d5d73 Mon Sep 17 00:00:00 2001 From: Dan Liang Date: Wed, 23 Jul 2008 21:27:25 -0400 Subject: Input: add driver for Atmel integrated touchscreen controller The AT91SAM9RL SoC integrates a Touchscreen Controller which can trigger ADC conversion periodically. Signed-off-by: Justin Waters Signed-off-by: Dan Liang Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 12 ++ drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/atmel_tsadcc.c | 332 +++++++++++++++++++++++++++++++ 3 files changed, 345 insertions(+) create mode 100644 drivers/input/touchscreen/atmel_tsadcc.c (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index e5736652157..6e60a97a234 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -205,6 +205,18 @@ config TOUCHSCREEN_TOUCHWIN To compile this driver as a module, choose M here: the module will be called touchwin. +config TOUCHSCREEN_ATMEL_TSADCC + tristate "Atmel Touchscreen Interface" + depends on ARCH_AT91SAM9RL + help + Say Y here if you have a 4-wire touchscreen connected to the + ADC Controller on your Atmel SoC (such as the AT91SAM9RL). + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called atmel_tsadcc. + config TOUCHSCREEN_UCB1400 tristate "Philips UCB1400 touchscreen" select AC97_BUS diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 39a804cd80f..15cf2907948 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -7,6 +7,7 @@ wm97xx-ts-y := wm97xx-core.o obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o +obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c new file mode 100644 index 00000000000..eee126b19e8 --- /dev/null +++ b/drivers/input/touchscreen/atmel_tsadcc.c @@ -0,0 +1,332 @@ +/* + * Atmel Touch Screen Driver + * + * Copyright (c) 2008 ATMEL + * Copyright (c) 2008 Dan Liang + * Copyright (c) 2008 TimeSys Corporation + * Copyright (c) 2008 Justin Waters + * + * Based on touchscreen code from Atmel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */ + +#define ATMEL_TSADCC_CR 0x00 /* Control register */ +#define ATMEL_TSADCC_SWRST (1 << 0) /* Software Reset*/ +#define ATMEL_TSADCC_START (1 << 1) /* Start conversion */ + +#define ATMEL_TSADCC_MR 0x04 /* Mode register */ +#define ATMEL_TSADCC_TSAMOD (3 << 0) /* ADC mode */ +#define ATMEL_TSADCC_TSAMOD_ADC_ONLY_MODE (0x0) /* ADC Mode */ +#define ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE (0x1) /* Touch Screen Only Mode */ +#define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */ +#define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */ +#define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */ +#define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */ +#define ATMEL_TSADCC_STARTUP (0x7f << 16) /* Start Up time */ +#define ATMEL_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */ +#define ATMEL_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */ + +#define ATMEL_TSADCC_TRGR 0x08 /* Trigger register */ +#define ATMEL_TSADCC_TRGMOD (7 << 0) /* Trigger mode */ +#define ATMEL_TSADCC_TRGMOD_NONE (0 << 0) +#define ATMEL_TSADCC_TRGMOD_EXT_RISING (1 << 0) +#define ATMEL_TSADCC_TRGMOD_EXT_FALLING (2 << 0) +#define ATMEL_TSADCC_TRGMOD_EXT_ANY (3 << 0) +#define ATMEL_TSADCC_TRGMOD_PENDET (4 << 0) +#define ATMEL_TSADCC_TRGMOD_PERIOD (5 << 0) +#define ATMEL_TSADCC_TRGMOD_CONTINUOUS (6 << 0) +#define ATMEL_TSADCC_TRGPER (0xffff << 16) /* Trigger period */ + +#define ATMEL_TSADCC_TSR 0x0C /* Touch Screen register */ +#define ATMEL_TSADCC_TSFREQ (0xf << 0) /* TS Frequency in Interleaved mode */ +#define ATMEL_TSADCC_TSSHTIM (0xf << 24) /* Sample & Hold time */ + +#define ATMEL_TSADCC_CHER 0x10 /* Channel Enable register */ +#define ATMEL_TSADCC_CHDR 0x14 /* Channel Disable register */ +#define ATMEL_TSADCC_CHSR 0x18 /* Channel Status register */ +#define ATMEL_TSADCC_CH(n) (1 << (n)) /* Channel number */ + +#define ATMEL_TSADCC_SR 0x1C /* Status register */ +#define ATMEL_TSADCC_EOC(n) (1 << ((n)+0)) /* End of conversion for channel N */ +#define ATMEL_TSADCC_OVRE(n) (1 << ((n)+8)) /* Overrun error for channel N */ +#define ATMEL_TSADCC_DRDY (1 << 16) /* Data Ready */ +#define ATMEL_TSADCC_GOVRE (1 << 17) /* General Overrun Error */ +#define ATMEL_TSADCC_ENDRX (1 << 18) /* End of RX Buffer */ +#define ATMEL_TSADCC_RXBUFF (1 << 19) /* TX Buffer full */ +#define ATMEL_TSADCC_PENCNT (1 << 20) /* Pen contact */ +#define ATMEL_TSADCC_NOCNT (1 << 21) /* No contact */ + +#define ATMEL_TSADCC_LCDR 0x20 /* Last Converted Data register */ +#define ATMEL_TSADCC_DATA (0x3ff << 0) /* Channel data */ + +#define ATMEL_TSADCC_IER 0x24 /* Interrupt Enable register */ +#define ATMEL_TSADCC_IDR 0x28 /* Interrupt Disable register */ +#define ATMEL_TSADCC_IMR 0x2C /* Interrupt Mask register */ +#define ATMEL_TSADCC_CDR0 0x30 /* Channel Data 0 */ +#define ATMEL_TSADCC_CDR1 0x34 /* Channel Data 1 */ +#define ATMEL_TSADCC_CDR2 0x38 /* Channel Data 2 */ +#define ATMEL_TSADCC_CDR3 0x3C /* Channel Data 3 */ +#define ATMEL_TSADCC_CDR4 0x40 /* Channel Data 4 */ +#define ATMEL_TSADCC_CDR5 0x44 /* Channel Data 5 */ + +#define ADC_CLOCK 1000000 + +struct atmel_tsadcc { + struct input_dev *input; + char phys[32]; + struct clk *clk; + int irq; +}; + +static void __iomem *tsc_base; + +#define atmel_tsadcc_read(reg) __raw_readl(tsc_base + (reg)) +#define atmel_tsadcc_write(reg, val) __raw_writel((val), tsc_base + (reg)) + +static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) +{ + struct input_dev *input_dev = ((struct atmel_tsadcc *)dev)->input; + + unsigned int absx; + unsigned int absy; + unsigned int status; + unsigned int reg; + + status = atmel_tsadcc_read(ATMEL_TSADCC_SR); + status &= atmel_tsadcc_read(ATMEL_TSADCC_IMR); + + if (status & ATMEL_TSADCC_NOCNT) { + /* Contact lost */ + reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC; + + atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); + atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE); + atmel_tsadcc_write(ATMEL_TSADCC_IDR, + ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT); + atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); + + input_report_key(input_dev, BTN_TOUCH, 0); + input_sync(input_dev); + + } else if (status & ATMEL_TSADCC_PENCNT) { + /* Pen detected */ + reg = atmel_tsadcc_read(ATMEL_TSADCC_MR); + reg &= ~ATMEL_TSADCC_PENDBC; + + atmel_tsadcc_write(ATMEL_TSADCC_IDR, ATMEL_TSADCC_PENCNT); + atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); + atmel_tsadcc_write(ATMEL_TSADCC_IER, + ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT); + atmel_tsadcc_write(ATMEL_TSADCC_TRGR, + ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FFF << 16)); + + } else if (status & ATMEL_TSADCC_EOC(3)) { + /* Conversion finished */ + + absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10; + absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2); + + absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10; + absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0); + + input_report_abs(input_dev, ABS_X, absx); + input_report_abs(input_dev, ABS_Y, absy); + input_report_key(input_dev, BTN_TOUCH, 1); + input_sync(input_dev); + } + + return IRQ_HANDLED; +} + +/* + * The functions for inserting/removing us as a module. + */ + +static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) +{ + struct atmel_tsadcc *ts_dev; + struct input_dev *input_dev; + struct resource *res; + int err = 0; + unsigned int prsc; + unsigned int reg; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "no mmio resource defined.\n"); + return -ENXIO; + } + + /* Allocate memory for device */ + ts_dev = kzalloc(sizeof(struct atmel_tsadcc), GFP_KERNEL); + if (!ts_dev) { + dev_err(&pdev->dev, "failed to allocate memory.\n"); + return -ENOMEM; + } + platform_set_drvdata(pdev, ts_dev); + + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&pdev->dev, "failed to allocate input device.\n"); + err = -EBUSY; + goto err_free_mem; + } + + ts_dev->irq = platform_get_irq(pdev, 0); + if (ts_dev->irq < 0) { + dev_err(&pdev->dev, "no irq ID is designated.\n"); + err = -ENODEV; + goto err_free_dev; + } + + if (!request_mem_region(res->start, res->end - res->start + 1, + "atmel tsadcc regs")) { + dev_err(&pdev->dev, "resources is unavailable.\n"); + err = -EBUSY; + goto err_free_dev; + } + + tsc_base = ioremap(res->start, res->end - res->start + 1); + if (!tsc_base) { + dev_err(&pdev->dev, "failed to map registers.\n"); + err = -ENOMEM; + goto err_release_mem; + } + + err = request_irq(ts_dev->irq, atmel_tsadcc_interrupt, IRQF_DISABLED, + pdev->dev.driver->name, ts_dev); + if (err) { + dev_err(&pdev->dev, "failed to allocate irq.\n"); + goto err_unmap_regs; + } + + ts_dev->clk = clk_get(&pdev->dev, "tsc_clk"); + if (IS_ERR(ts_dev->clk)) { + dev_err(&pdev->dev, "failed to get ts_clk\n"); + err = PTR_ERR(ts_dev->clk); + goto err_free_irq; + } + + ts_dev->input = input_dev; + + snprintf(ts_dev->phys, sizeof(ts_dev->phys), + "%s/input0", pdev->dev.bus_id); + + input_dev->name = "atmel touch screen controller"; + input_dev->phys = ts_dev->phys; + input_dev->dev.parent = &pdev->dev; + + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(input_dev, ABS_X, 0, 0x3FF, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 0x3FF, 0, 0); + + /* clk_enable() always returns 0, no need to check it */ + clk_enable(ts_dev->clk); + + prsc = clk_get_rate(ts_dev->clk); + dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc); + + prsc = prsc / ADC_CLOCK / 2 - 1; + + reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE | + ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* Normal Mode */ + ((0x01 << 6) & ATMEL_TSADCC_PENDET) | /* Enable Pen Detect */ + ((prsc << 8) & ATMEL_TSADCC_PRESCAL) | /* PRESCAL */ + ((0x13 << 16) & ATMEL_TSADCC_STARTUP) | /* STARTUP */ + ((0x0F << 28) & ATMEL_TSADCC_PENDBC); /* PENDBC */ + + atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST); + atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); + atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE); + atmel_tsadcc_write(ATMEL_TSADCC_TSR, (0x3 << 24) & ATMEL_TSADCC_TSSHTIM); + + atmel_tsadcc_read(ATMEL_TSADCC_SR); + atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); + + /* All went ok, so register to the input system */ + err = input_register_device(input_dev); + if (err) + goto err_fail; + + return 0; + +err_fail: + clk_disable(ts_dev->clk); + clk_put(ts_dev->clk); +err_free_irq: + free_irq(ts_dev->irq, ts_dev); +err_unmap_regs: + iounmap(tsc_base); +err_release_mem: + release_mem_region(res->start, res->end - res->start + 1); +err_free_dev: + input_free_device(ts_dev->input); +err_free_mem: + kfree(ts_dev); + return err; +} + +static int __devexit atmel_tsadcc_remove(struct platform_device *pdev) +{ + struct atmel_tsadcc *ts_dev = dev_get_drvdata(&pdev->dev); + struct resource *res; + + free_irq(ts_dev->irq, ts_dev); + + input_unregister_device(ts_dev->input); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + iounmap(tsc_base); + release_mem_region(res->start, res->end - res->start + 1); + + clk_disable(ts_dev->clk); + clk_put(ts_dev->clk); + + kfree(ts_dev); + + return 0; +} + +static struct platform_driver atmel_tsadcc_driver = { + .probe = atmel_tsadcc_probe, + .remove = __devexit_p(atmel_tsadcc_remove), + .driver = { + .name = "atmel_tsadcc", + }, +}; + +static int __init atmel_tsadcc_init(void) +{ + return platform_driver_register(&atmel_tsadcc_driver); +} + +static void __exit atmel_tsadcc_exit(void) +{ + platform_driver_unregister(&atmel_tsadcc_driver); +} + +module_init(atmel_tsadcc_init); +module_exit(atmel_tsadcc_exit); + + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Atmel TouchScreen Driver"); +MODULE_AUTHOR("Dan Liang "); + -- cgit v1.2.3 From 8fa89bf5de066b11190ac804903021700c2b1185 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 14 Jul 2008 22:56:55 +0200 Subject: mv643xx_eth: fix TX hang erratum workaround The previously merged TX hang erratum workaround ("mv643xx_eth: work around TX hang hardware issue") assumes that TX_END interrupts are delivered simultaneously with or after their corresponding TX interrupts, but this is not always true in practise. In particular, it appears that TX_END interrupts are issued as soon as descriptor fetch returns an invalid descriptor, which may happen before earlier descriptors have been fully transmitted and written back to memory as being done. This hardware behavior can lead to a situation where the current driver code mistakenly assumes that the MAC has given up transmitting before noticing the packets that it is in fact still currently working on, causing the driver to re-kick the transmit queue, which will only cause the MAC to re-fetch the invalid head descriptor, and generate another TX_END interrupt, et cetera, until the packets in the pipe finally finish transmitting and have their descriptors written back to memory, which will then finally break the loop. Fix this by having the erratum workaround not check the 'number of unfinished descriptor', but instead, to compare the software's idea of what the head descriptor pointer should be to the hardware's head descriptor pointer (which is updated on the same conditions as the TX_END interupt is generated on, i.e. possibly before all previous descriptors have been transmitted and written back). Signed-off-by: Lennert Buytenhek --- drivers/net/mv643xx_eth.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 8a97a0066a8..910920e2125 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -96,6 +96,7 @@ static char mv643xx_eth_driver_version[] = "1.1"; #define TX_BW_MTU(p) (0x0458 + ((p) << 10)) #define TX_BW_BURST(p) (0x045c + ((p) << 10)) #define INT_CAUSE(p) (0x0460 + ((p) << 10)) +#define INT_TX_END_0 0x00080000 #define INT_TX_END 0x07f80000 #define INT_RX 0x0007fbfc #define INT_EXT 0x00000002 @@ -706,6 +707,7 @@ static inline __be16 sum16_as_be(__sum16 sum) static void txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb) { + struct mv643xx_eth_private *mp = txq_to_mp(txq); int nr_frags = skb_shinfo(skb)->nr_frags; int tx_index; struct tx_desc *desc; @@ -759,6 +761,10 @@ static void txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb) wmb(); desc->cmd_sts = cmd_sts; + /* clear TX_END interrupt status */ + wrl(mp, INT_CAUSE(mp->port_num), ~(INT_TX_END_0 << txq->index)); + rdl(mp, INT_CAUSE(mp->port_num)); + /* ensure all descriptors are written before poking hardware */ wmb(); txq_enable(txq); @@ -1684,7 +1690,6 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) struct mv643xx_eth_private *mp = netdev_priv(dev); u32 int_cause; u32 int_cause_ext; - u32 txq_active; int_cause = rdl(mp, INT_CAUSE(mp->port_num)) & (INT_TX_END | INT_RX | INT_EXT); @@ -1743,8 +1748,6 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) } #endif - txq_active = rdl(mp, TXQ_COMMAND(mp->port_num)); - /* * TxBuffer or TxError set for any of the 8 queues? */ @@ -1754,6 +1757,14 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) for (i = 0; i < 8; i++) if (mp->txq_mask & (1 << i)) txq_reclaim(mp->txq + i, 0); + + /* + * Enough space again in the primary TX queue for a + * full packet? + */ + spin_lock(&mp->lock); + __txq_maybe_wake(mp->txq + mp->txq_primary); + spin_unlock(&mp->lock); } /* @@ -1763,19 +1774,25 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) int i; wrl(mp, INT_CAUSE(mp->port_num), ~(int_cause & INT_TX_END)); + + spin_lock(&mp->lock); for (i = 0; i < 8; i++) { struct tx_queue *txq = mp->txq + i; - if (txq->tx_desc_count && !((txq_active >> i) & 1)) + u32 hw_desc_ptr; + u32 expected_ptr; + + if ((int_cause & (INT_TX_END_0 << i)) == 0) + continue; + + hw_desc_ptr = + rdl(mp, TXQ_CURRENT_DESC_PTR(mp->port_num, i)); + expected_ptr = (u32)txq->tx_desc_dma + + txq->tx_curr_desc * sizeof(struct tx_desc); + + if (hw_desc_ptr != expected_ptr) txq_enable(txq); } - } - - /* - * Enough space again in the primary TX queue for a full packet? - */ - if (int_cause_ext & INT_EXT_TX) { - struct tx_queue *txq = mp->txq + mp->txq_primary; - __txq_maybe_wake(txq); + spin_unlock(&mp->lock); } return IRQ_HANDLED; -- cgit v1.2.3 From 6b368f6859c80343e5d7c6e2a7c49df0a8a273c1 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 11 Jul 2008 19:38:34 +0200 Subject: mv643xx_eth: prevent breakage when link goes down during transmit When the ethernet link goes down while mv643xx_eth is transmitting data, transmit DMA can stop before all queued transmit descriptors have been processed. But even the descriptors that _have_ been processed might not be properly marked as done before the transmit DMA unit shuts down. Then when the link comes up again, the hardware transmit pointer might have advanced while not all previous packet descriptors have been marked as transmitted, causing software transmit reclaim to hang waiting for the hardware to finish transmitting a descriptor that it has already skipped. This patch forcibly reclaims all packets on the transmit ring on a link down interrupt, and then resyncs the hardware transmit pointer to what the software's idea of the first free descriptor is. Also, we need to prevent re-waking the transmit queue if we get a 'transmit done' interrupt at the same time as a 'link down' interrupt, which this patch does as well. Signed-off-by: Lennert Buytenhek --- drivers/net/mv643xx_eth.c | 57 +++++++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 910920e2125..d7620c50efb 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -405,6 +405,17 @@ static void rxq_disable(struct rx_queue *rxq) udelay(10); } +static void txq_reset_hw_ptr(struct tx_queue *txq) +{ + struct mv643xx_eth_private *mp = txq_to_mp(txq); + int off = TXQ_CURRENT_DESC_PTR(mp->port_num, txq->index); + u32 addr; + + addr = (u32)txq->tx_desc_dma; + addr += txq->tx_curr_desc * sizeof(struct tx_desc); + wrl(mp, off, addr); +} + static void txq_enable(struct tx_queue *txq) { struct mv643xx_eth_private *mp = txq_to_mp(txq); @@ -1545,8 +1556,11 @@ static int txq_init(struct mv643xx_eth_private *mp, int index) tx_desc = (struct tx_desc *)txq->tx_desc_area; for (i = 0; i < txq->tx_ring_size; i++) { + struct tx_desc *txd = tx_desc + i; int nexti = (i + 1) % txq->tx_ring_size; - tx_desc[i].next_desc_ptr = txq->tx_desc_dma + + + txd->cmd_sts = 0; + txd->next_desc_ptr = txq->tx_desc_dma + nexti * sizeof(struct tx_desc); } @@ -1583,8 +1597,11 @@ static void txq_reclaim(struct tx_queue *txq, int force) desc = &txq->tx_desc_area[tx_index]; cmd_sts = desc->cmd_sts; - if (!force && (cmd_sts & BUFFER_OWNED_BY_DMA)) - break; + if (cmd_sts & BUFFER_OWNED_BY_DMA) { + if (!force) + break; + desc->cmd_sts = cmd_sts & ~BUFFER_OWNED_BY_DMA; + } txq->tx_used_desc = (tx_index + 1) % txq->tx_ring_size; txq->tx_desc_count--; @@ -1705,8 +1722,6 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) if (int_cause_ext & (INT_EXT_PHY | INT_EXT_LINK)) { if (mp->phy_addr == -1 || mii_link_ok(&mp->mii)) { - int i; - if (mp->phy_addr != -1) { struct ethtool_cmd cmd; @@ -1714,17 +1729,24 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) update_pscr(mp, cmd.speed, cmd.duplex); } - for (i = 0; i < 8; i++) - if (mp->txq_mask & (1 << i)) - txq_enable(mp->txq + i); - if (!netif_carrier_ok(dev)) { netif_carrier_on(dev); - __txq_maybe_wake(mp->txq + mp->txq_primary); + netif_wake_queue(dev); } } else if (netif_carrier_ok(dev)) { + int i; + netif_stop_queue(dev); netif_carrier_off(dev); + + for (i = 0; i < 8; i++) { + struct tx_queue *txq = mp->txq + i; + + if (mp->txq_mask & (1 << i)) { + txq_reclaim(txq, 1); + txq_reset_hw_ptr(txq); + } + } } } @@ -1762,9 +1784,11 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) * Enough space again in the primary TX queue for a * full packet? */ - spin_lock(&mp->lock); - __txq_maybe_wake(mp->txq + mp->txq_primary); - spin_unlock(&mp->lock); + if (netif_carrier_ok(dev)) { + spin_lock(&mp->lock); + __txq_maybe_wake(mp->txq + mp->txq_primary); + spin_unlock(&mp->lock); + } } /* @@ -1851,16 +1875,11 @@ static void port_start(struct mv643xx_eth_private *mp) tx_set_rate(mp, 1000000000, 16777216); for (i = 0; i < 8; i++) { struct tx_queue *txq = mp->txq + i; - int off = TXQ_CURRENT_DESC_PTR(mp->port_num, i); - u32 addr; if ((mp->txq_mask & (1 << i)) == 0) continue; - addr = (u32)txq->tx_desc_dma; - addr += txq->tx_curr_desc * sizeof(struct tx_desc); - wrl(mp, off, addr); - + txq_reset_hw_ptr(txq); txq_set_rate(txq, 1000000000, 16777216); txq_set_fixed_prio_mode(txq); } -- cgit v1.2.3 From 4dfc1c87af46f9d8abf2ef78a4e22891d7a564c3 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 15 Jul 2008 13:34:51 +0200 Subject: mv643xx_eth: fix transmit-reclaim-in-napi-poll The mv643xx_eth driver allows doing transmit reclaim from within the napi poll routine, but after doing reclaim, it would forget to check the free transmit descriptor count and wake up the transmit queue if the reclaim caused enough descriptors for a new packet to become available. This would cause the netdev watchdog to occasionally kick in during certain workloads with combined receive and transmit traffic. Fix this by adding a wakeup check identical to the one in the interrupt handler to the napi poll routine. Signed-off-by: Lennert Buytenhek --- drivers/net/mv643xx_eth.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index d7620c50efb..3211369a432 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -626,6 +626,12 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget) for (i = 0; i < 8; i++) if (mp->txq_mask & (1 << i)) txq_reclaim(mp->txq + i, 0); + + if (netif_carrier_ok(mp->dev)) { + spin_lock(&mp->lock); + __txq_maybe_wake(mp->txq + mp->txq_primary); + spin_unlock(&mp->lock); + } } #endif -- cgit v1.2.3 From 65193a91fc60fdb79e392c9842c10552a1fa3e1c Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 11 Jul 2008 00:39:41 +0200 Subject: mv643xx_eth: don't fiddle with maximum receive packet size setting The maximum receive packet size field in the Port Serial Control register controls at what size received packets are flagged overlength in the receive descriptor, but it doesn't prevent overlength packets from being DMAd to memory and signaled to the host like other received packets. mv643xx_eth does not support receiving jumbo frames in 10/100 mode, but setting the packet threshold to larger than 1522 bytes in 10/100 mode won't cause breakage by itself. If we really want to enforce maximum packet size on the receiving end instead of on the sending end where it should be done, we can always just add a length check to the software receive handler instead of relying on the hardware to do the comparison for us. What's more, changing the maximum packet size field requires temporarily disabling the RX/TX paths. So once the link comes up in 10/100 Mb/s mode or 1000 Mb/s mode, we'd have to disable it again just to set the right maximum packet size field (1522 in 10/100 Mb/s mode or 9700 in 1000 Mb/s mode), just so that we can offload one comparison operation to hardware that we might as well do in software, assuming that we'd want to do it at all. Contrary to what the documentation suggests, there is no harm in just setting a 9700 byte maximum packet size in 10/100 mode, so use the maximum maximum packet size for all modes. Signed-off-by: Lennert Buytenhek --- drivers/net/mv643xx_eth.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 3211369a432..207d4391a6d 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -154,7 +154,6 @@ static char mv643xx_eth_driver_version[] = "1.1"; #define SET_MII_SPEED_TO_100 (1 << 24) #define SET_GMII_SPEED_TO_1000 (1 << 23) #define SET_FULL_DUPLEX_MODE (1 << 21) -#define MAX_RX_PACKET_1522BYTE (1 << 17) #define MAX_RX_PACKET_9700BYTE (5 << 17) #define MAX_RX_PACKET_MASK (7 << 17) #define DISABLE_AUTO_NEG_SPEED_GMII (1 << 13) @@ -1674,13 +1673,12 @@ static void update_pscr(struct mv643xx_eth_private *mp, int speed, int duplex) SET_FULL_DUPLEX_MODE | MAX_RX_PACKET_MASK); - if (speed == SPEED_1000) { - pscr_n |= SET_GMII_SPEED_TO_1000 | MAX_RX_PACKET_9700BYTE; - } else { - if (speed == SPEED_100) - pscr_n |= SET_MII_SPEED_TO_100; - pscr_n |= MAX_RX_PACKET_1522BYTE; - } + pscr_n |= MAX_RX_PACKET_9700BYTE; + + if (speed == SPEED_1000) + pscr_n |= SET_GMII_SPEED_TO_1000; + else if (speed == SPEED_100) + pscr_n |= SET_MII_SPEED_TO_100; if (duplex == DUPLEX_FULL) pscr_n |= SET_FULL_DUPLEX_MODE; -- cgit v1.2.3 From ae9ae06443f7bfa4f013c0e2c035d549e999ad3e Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 15 Jul 2008 02:15:24 +0200 Subject: mv643xx_eth: also check TX_IN_PROGRESS when disabling transmit path The recommended sequence for waiting for the transmit path to clear after disabling all of the transmit queues is to wait for the TX_FIFO_EMPTY bit in the Port Status register to become set as well as the TX_IN_PROGRESS bit to clear. Signed-off-by: Lennert Buytenhek --- drivers/net/mv643xx_eth.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 207d4391a6d..c700c1f494e 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -90,6 +90,7 @@ static char mv643xx_eth_driver_version[] = "1.1"; #define PORT_SERIAL_CONTROL(p) (0x043c + ((p) << 10)) #define PORT_STATUS(p) (0x0444 + ((p) << 10)) #define TX_FIFO_EMPTY 0x00000400 +#define TX_IN_PROGRESS 0x00000080 #define TXQ_COMMAND(p) (0x0448 + ((p) << 10)) #define TXQ_FIX_PRIO_CONF(p) (0x044c + ((p) << 10)) #define TX_BW_RATE(p) (0x0450 + ((p) << 10)) @@ -2039,8 +2040,14 @@ static void port_reset(struct mv643xx_eth_private *mp) if (mp->txq_mask & (1 << i)) txq_disable(mp->txq + i); } - while (!(rdl(mp, PORT_STATUS(mp->port_num)) & TX_FIFO_EMPTY)) + + while (1) { + u32 ps = rdl(mp, PORT_STATUS(mp->port_num)); + + if ((ps & (TX_IN_PROGRESS | TX_FIFO_EMPTY)) == TX_FIFO_EMPTY) + break; udelay(10); + } /* Reset the Enable bit in the Configuration Register */ data = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num)); -- cgit v1.2.3 From cd4ccf76bfd2c36d351e68be7e6a597268f98a1a Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 10 Jul 2008 14:40:51 +0200 Subject: mv643xx_eth: use longer DMA bursts The mv643xx_eth driver is limiting DMA bursts to 32 bytes, while using the largest burst size (128 bytes) gives a couple percentage points performance improvement in throughput tests, and the docs say that the 128 byte default should not need to be changed, so use 128 byte bursts instead. Signed-off-by: Lennert Buytenhek --- drivers/net/mv643xx_eth.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index c700c1f494e..9d200568d88 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -129,21 +129,21 @@ static char mv643xx_eth_driver_version[] = "1.1"; /* * SDMA configuration register. */ -#define RX_BURST_SIZE_4_64BIT (2 << 1) +#define RX_BURST_SIZE_16_64BIT (4 << 1) #define BLM_RX_NO_SWAP (1 << 4) #define BLM_TX_NO_SWAP (1 << 5) -#define TX_BURST_SIZE_4_64BIT (2 << 22) +#define TX_BURST_SIZE_16_64BIT (4 << 22) #if defined(__BIG_ENDIAN) #define PORT_SDMA_CONFIG_DEFAULT_VALUE \ - RX_BURST_SIZE_4_64BIT | \ - TX_BURST_SIZE_4_64BIT + RX_BURST_SIZE_16_64BIT | \ + TX_BURST_SIZE_16_64BIT #elif defined(__LITTLE_ENDIAN) #define PORT_SDMA_CONFIG_DEFAULT_VALUE \ - RX_BURST_SIZE_4_64BIT | \ + RX_BURST_SIZE_16_64BIT | \ BLM_RX_NO_SWAP | \ BLM_TX_NO_SWAP | \ - TX_BURST_SIZE_4_64BIT + TX_BURST_SIZE_16_64BIT #else #error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined #endif -- cgit v1.2.3 From 7f106c1d050c085c84d148ba56293e60b2c4e756 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 15 Jul 2008 02:28:47 +0200 Subject: mv643xx_eth: use symbolic MII register addresses and values Instead of hardcoding MII register addresses and values, use the symbolic constants defined in linux/mii.h. Signed-off-by: Lennert Buytenhek --- drivers/net/mv643xx_eth.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 9d200568d88..5bed6b33c7b 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1831,14 +1831,14 @@ static void phy_reset(struct mv643xx_eth_private *mp) { unsigned int data; - smi_reg_read(mp, mp->phy_addr, 0, &data); - data |= 0x8000; - smi_reg_write(mp, mp->phy_addr, 0, data); + smi_reg_read(mp, mp->phy_addr, MII_BMCR, &data); + data |= BMCR_RESET; + smi_reg_write(mp, mp->phy_addr, MII_BMCR, data); do { udelay(1); - smi_reg_read(mp, mp->phy_addr, 0, &data); - } while (data & 0x8000); + smi_reg_read(mp, mp->phy_addr, MII_BMCR, &data); + } while (data & BMCR_RESET); } static void port_start(struct mv643xx_eth_private *mp) @@ -2385,14 +2385,14 @@ static int phy_detect(struct mv643xx_eth_private *mp) unsigned int data; unsigned int data2; - smi_reg_read(mp, mp->phy_addr, 0, &data); - smi_reg_write(mp, mp->phy_addr, 0, data ^ 0x1000); + smi_reg_read(mp, mp->phy_addr, MII_BMCR, &data); + smi_reg_write(mp, mp->phy_addr, MII_BMCR, data ^ BMCR_ANENABLE); - smi_reg_read(mp, mp->phy_addr, 0, &data2); - if (((data ^ data2) & 0x1000) == 0) + smi_reg_read(mp, mp->phy_addr, MII_BMCR, &data2); + if (((data ^ data2) & BMCR_ANENABLE) == 0) return -ENODEV; - smi_reg_write(mp, mp->phy_addr, 0, data); + smi_reg_write(mp, mp->phy_addr, MII_BMCR, data); return 0; } -- cgit v1.2.3 From 7dde154d3d0d9701ecfb5533017a8f1a20bb4214 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 15 Jul 2008 12:20:30 +0200 Subject: mv643xx_eth: print driver version on init Print the mv643xx_eth driver version on init to help debugging. Signed-off-by: Lennert Buytenhek --- drivers/net/mv643xx_eth.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 5bed6b33c7b..006ad45ddb8 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2249,7 +2249,8 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) int ret; if (!mv643xx_eth_version_printed++) - printk(KERN_NOTICE "MV-643xx 10/100/1000 Ethernet Driver\n"); + printk(KERN_NOTICE "MV-643xx 10/100/1000 ethernet " + "driver version %s\n", mv643xx_eth_driver_version); ret = -EINVAL; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- cgit v1.2.3 From 81600eea98789da09a32de69ca9d3be8b9503c54 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 14 Jul 2008 14:29:40 +0200 Subject: mv643xx_eth: use auto phy polling for configuring (R)(G)MII interface The mv643xx_eth hardware has a provision for polling the PHY's MII management registers to obtain the (R)(G)MII interface speed (10/100/1000) and duplex (half/full) and pause (off/symmetric) settings to use to talk to the PHY. The driver currently does not make use of this feature. Instead, whenever there is a link status change event, it reads the current link parameters from the PHY, and programs those parameters into the mv643xx_eth MAC by hand. This patch switches the mv643xx_eth driver to letting the MAC auto-determine the (R)(G)MII link parameters by PHY polling, if there is a PHY present. For PHYless ports (when e.g. the (R)(G)MII interface is connected to a hardware switch), we keep hardcoding the MII interface parameters. Signed-off-by: Lennert Buytenhek --- drivers/net/mv643xx_eth.c | 140 ++++++++++++++++++++++------------------------ 1 file changed, 66 insertions(+), 74 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 006ad45ddb8..29d4fe37cd5 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -91,6 +91,7 @@ static char mv643xx_eth_driver_version[] = "1.1"; #define PORT_STATUS(p) (0x0444 + ((p) << 10)) #define TX_FIFO_EMPTY 0x00000400 #define TX_IN_PROGRESS 0x00000080 +#define LINK_UP 0x00000002 #define TXQ_COMMAND(p) (0x0448 + ((p) << 10)) #define TXQ_FIX_PRIO_CONF(p) (0x044c + ((p) << 10)) #define TX_BW_RATE(p) (0x0450 + ((p) << 10)) @@ -156,7 +157,6 @@ static char mv643xx_eth_driver_version[] = "1.1"; #define SET_GMII_SPEED_TO_1000 (1 << 23) #define SET_FULL_DUPLEX_MODE (1 << 21) #define MAX_RX_PACKET_9700BYTE (5 << 17) -#define MAX_RX_PACKET_MASK (7 << 17) #define DISABLE_AUTO_NEG_SPEED_GMII (1 << 13) #define DO_NOT_FORCE_LINK_FAIL (1 << 10) #define SERIAL_PORT_CONTROL_RESERVED (1 << 9) @@ -1135,10 +1135,28 @@ static int mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd * static int mv643xx_eth_get_settings_phyless(struct net_device *dev, struct ethtool_cmd *cmd) { + struct mv643xx_eth_private *mp = netdev_priv(dev); + u32 port_status; + + port_status = rdl(mp, PORT_STATUS(mp->port_num)); + cmd->supported = SUPPORTED_MII; cmd->advertising = ADVERTISED_MII; - cmd->speed = SPEED_1000; - cmd->duplex = DUPLEX_FULL; + switch (port_status & PORT_SPEED_MASK) { + case PORT_SPEED_10: + cmd->speed = SPEED_10; + break; + case PORT_SPEED_100: + cmd->speed = SPEED_100; + break; + case PORT_SPEED_1000: + cmd->speed = SPEED_1000; + break; + default: + cmd->speed = -1; + break; + } + cmd->duplex = (port_status & FULL_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; cmd->port = PORT_MII; cmd->phy_address = 0; cmd->transceiver = XCVR_INTERNAL; @@ -1661,51 +1679,6 @@ static void txq_deinit(struct tx_queue *txq) /* netdev ops and related ***************************************************/ -static void update_pscr(struct mv643xx_eth_private *mp, int speed, int duplex) -{ - u32 pscr_o; - u32 pscr_n; - - pscr_o = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num)); - - /* clear speed, duplex and rx buffer size fields */ - pscr_n = pscr_o & ~(SET_MII_SPEED_TO_100 | - SET_GMII_SPEED_TO_1000 | - SET_FULL_DUPLEX_MODE | - MAX_RX_PACKET_MASK); - - pscr_n |= MAX_RX_PACKET_9700BYTE; - - if (speed == SPEED_1000) - pscr_n |= SET_GMII_SPEED_TO_1000; - else if (speed == SPEED_100) - pscr_n |= SET_MII_SPEED_TO_100; - - if (duplex == DUPLEX_FULL) - pscr_n |= SET_FULL_DUPLEX_MODE; - - if (pscr_n != pscr_o) { - if ((pscr_o & SERIAL_PORT_ENABLE) == 0) - wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr_n); - else { - int i; - - for (i = 0; i < 8; i++) - if (mp->txq_mask & (1 << i)) - txq_disable(mp->txq + i); - - pscr_o &= ~SERIAL_PORT_ENABLE; - wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr_o); - wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr_n); - wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr_n); - - for (i = 0; i < 8; i++) - if (mp->txq_mask & (1 << i)) - txq_enable(mp->txq + i); - } - } -} - static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; @@ -1726,14 +1699,7 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) } if (int_cause_ext & (INT_EXT_PHY | INT_EXT_LINK)) { - if (mp->phy_addr == -1 || mii_link_ok(&mp->mii)) { - if (mp->phy_addr != -1) { - struct ethtool_cmd cmd; - - mii_ethtool_gset(&mp->mii, &cmd); - update_pscr(mp, cmd.speed, cmd.duplex); - } - + if (rdl(mp, PORT_STATUS(mp->port_num)) & LINK_UP) { if (!netif_carrier_ok(dev)) { netif_carrier_on(dev); netif_wake_queue(dev); @@ -1846,23 +1812,6 @@ static void port_start(struct mv643xx_eth_private *mp) u32 pscr; int i; - /* - * Configure basic link parameters. - */ - pscr = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num)); - pscr &= ~(SERIAL_PORT_ENABLE | FORCE_LINK_PASS); - wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); - pscr |= DISABLE_AUTO_NEG_FOR_FLOW_CTRL | - DISABLE_AUTO_NEG_SPEED_GMII | - DISABLE_AUTO_NEG_FOR_DUPLEX | - DO_NOT_FORCE_LINK_FAIL | - SERIAL_PORT_CONTROL_RESERVED; - wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); - pscr |= SERIAL_PORT_ENABLE; - wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); - - wrl(mp, SDMA_CONFIG(mp->port_num), PORT_SDMA_CONFIG_DEFAULT_VALUE); - /* * Perform PHY reset, if there is a PHY. */ @@ -1874,6 +1823,21 @@ static void port_start(struct mv643xx_eth_private *mp) mv643xx_eth_set_settings(mp->dev, &cmd); } + /* + * Configure basic link parameters. + */ + pscr = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num)); + + pscr |= SERIAL_PORT_ENABLE; + wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); + + pscr |= DO_NOT_FORCE_LINK_FAIL; + if (mp->phy_addr == -1) + pscr |= FORCE_LINK_PASS; + wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); + + wrl(mp, SDMA_CONFIG(mp->port_num), PORT_SDMA_CONFIG_DEFAULT_VALUE); + /* * Configure TX path and queues. */ @@ -2441,12 +2405,39 @@ static int phy_init(struct mv643xx_eth_private *mp, cmd.duplex = pd->duplex; } - update_pscr(mp, cmd.speed, cmd.duplex); mv643xx_eth_set_settings(mp->dev, &cmd); return 0; } +static void init_pscr(struct mv643xx_eth_private *mp, int speed, int duplex) +{ + u32 pscr; + + pscr = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num)); + if (pscr & SERIAL_PORT_ENABLE) { + pscr &= ~SERIAL_PORT_ENABLE; + wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); + } + + pscr = MAX_RX_PACKET_9700BYTE | SERIAL_PORT_CONTROL_RESERVED; + if (mp->phy_addr == -1) { + pscr |= DISABLE_AUTO_NEG_SPEED_GMII; + if (speed == SPEED_1000) + pscr |= SET_GMII_SPEED_TO_1000; + else if (speed == SPEED_100) + pscr |= SET_MII_SPEED_TO_100; + + pscr |= DISABLE_AUTO_NEG_FOR_FLOW_CTRL; + + pscr |= DISABLE_AUTO_NEG_FOR_DUPLEX; + if (duplex == DUPLEX_FULL) + pscr |= SET_FULL_DUPLEX_MODE; + } + + wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); +} + static int mv643xx_eth_probe(struct platform_device *pdev) { struct mv643xx_eth_platform_data *pd; @@ -2500,6 +2491,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) } else { SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops_phyless); } + init_pscr(mp, pd->speed, pd->duplex); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -- cgit v1.2.3 From 2f7eb47a7b9f703d4f7dfdab358df6ff1f2a2204 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 24 Jul 2008 06:22:59 +0200 Subject: mv643xx_eth: print message on link status change When there is a link status change (link or phy status interrupt), print a message notifying the user of the new link status. Signed-off-by: Lennert Buytenhek --- drivers/net/mv643xx_eth.c | 91 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 69 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 29d4fe37cd5..01dd3c505d2 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -91,6 +91,12 @@ static char mv643xx_eth_driver_version[] = "1.1"; #define PORT_STATUS(p) (0x0444 + ((p) << 10)) #define TX_FIFO_EMPTY 0x00000400 #define TX_IN_PROGRESS 0x00000080 +#define PORT_SPEED_MASK 0x00000030 +#define PORT_SPEED_1000 0x00000010 +#define PORT_SPEED_100 0x00000020 +#define PORT_SPEED_10 0x00000000 +#define FLOW_CONTROL_ENABLED 0x00000008 +#define FULL_DUPLEX 0x00000004 #define LINK_UP 0x00000002 #define TXQ_COMMAND(p) (0x0448 + ((p) << 10)) #define TXQ_FIX_PRIO_CONF(p) (0x044c + ((p) << 10)) @@ -1679,6 +1685,64 @@ static void txq_deinit(struct tx_queue *txq) /* netdev ops and related ***************************************************/ +static void handle_link_event(struct mv643xx_eth_private *mp) +{ + struct net_device *dev = mp->dev; + u32 port_status; + int speed; + int duplex; + int fc; + + port_status = rdl(mp, PORT_STATUS(mp->port_num)); + if (!(port_status & LINK_UP)) { + if (netif_carrier_ok(dev)) { + int i; + + printk(KERN_INFO "%s: link down\n", dev->name); + + netif_carrier_off(dev); + netif_stop_queue(dev); + + for (i = 0; i < 8; i++) { + struct tx_queue *txq = mp->txq + i; + + if (mp->txq_mask & (1 << i)) { + txq_reclaim(txq, 1); + txq_reset_hw_ptr(txq); + } + } + } + return; + } + + switch (port_status & PORT_SPEED_MASK) { + case PORT_SPEED_10: + speed = 10; + break; + case PORT_SPEED_100: + speed = 100; + break; + case PORT_SPEED_1000: + speed = 1000; + break; + default: + speed = -1; + break; + } + duplex = (port_status & FULL_DUPLEX) ? 1 : 0; + fc = (port_status & FLOW_CONTROL_ENABLED) ? 1 : 0; + + printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, " + "flow control %sabled\n", dev->name, + speed, duplex ? "full" : "half", + fc ? "en" : "dis"); + + if (!netif_carrier_ok(dev)) { + netif_carrier_on(dev); + netif_wake_queue(dev); + } +} + static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; @@ -1698,28 +1762,8 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) wrl(mp, INT_CAUSE_EXT(mp->port_num), ~int_cause_ext); } - if (int_cause_ext & (INT_EXT_PHY | INT_EXT_LINK)) { - if (rdl(mp, PORT_STATUS(mp->port_num)) & LINK_UP) { - if (!netif_carrier_ok(dev)) { - netif_carrier_on(dev); - netif_wake_queue(dev); - } - } else if (netif_carrier_ok(dev)) { - int i; - - netif_stop_queue(dev); - netif_carrier_off(dev); - - for (i = 0; i < 8; i++) { - struct tx_queue *txq = mp->txq + i; - - if (mp->txq_mask & (1 << i)) { - txq_reclaim(txq, 1); - txq_reset_hw_ptr(txq); - } - } - } - } + if (int_cause_ext & (INT_EXT_PHY | INT_EXT_LINK)) + handle_link_event(mp); /* * RxBuffer or RxError set for any of the 8 queues? @@ -1970,6 +2014,9 @@ static int mv643xx_eth_open(struct net_device *dev) napi_enable(&mp->napi); #endif + netif_carrier_off(dev); + netif_stop_queue(dev); + port_start(mp); set_rx_coal(mp, 0); -- cgit v1.2.3 From e32b66175072d75bde1ddca4227a6723ca17e0af Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 24 Jul 2008 06:22:59 +0200 Subject: mv643xx_eth: enable hardware TX checksumming with vlan tags Although mv643xx_eth has no hardware support for inserting a vlan tag by twiddling some bits in the TX descriptor, it does support hardware TX checksumming on packets where the IP header starts {a limited set of values other than 14} bytes into the packet. This patch sets mv643xx_eth's ->vlan_features to NETIF_F_SG | NETIF_F_IP_CSUM, which prevents the stack from checksumming vlan'ed packets in software, and if vlan tags are present on a transmitted packet, notifies the hardware of this fact by toggling the right bits in the TX descriptor. Signed-off-by: Lennert Buytenhek --- drivers/net/mv643xx_eth.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 01dd3c505d2..88bb1f1e806 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -235,6 +235,8 @@ struct tx_desc { #define GEN_IP_V4_CHECKSUM 0x00040000 #define GEN_TCP_UDP_CHECKSUM 0x00020000 #define UDP_FRAME 0x00010000 +#define MAC_HDR_EXTRA_4_BYTES 0x00008000 +#define MAC_HDR_EXTRA_8_BYTES 0x00000200 #define TX_IHL_SHIFT 11 @@ -757,12 +759,36 @@ static void txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb) desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE); if (skb->ip_summed == CHECKSUM_PARTIAL) { - BUG_ON(skb->protocol != htons(ETH_P_IP)); + int mac_hdr_len; + + BUG_ON(skb->protocol != htons(ETH_P_IP) && + skb->protocol != htons(ETH_P_8021Q)); cmd_sts |= GEN_TCP_UDP_CHECKSUM | GEN_IP_V4_CHECKSUM | ip_hdr(skb)->ihl << TX_IHL_SHIFT; + mac_hdr_len = (void *)ip_hdr(skb) - (void *)skb->data; + switch (mac_hdr_len - ETH_HLEN) { + case 0: + break; + case 4: + cmd_sts |= MAC_HDR_EXTRA_4_BYTES; + break; + case 8: + cmd_sts |= MAC_HDR_EXTRA_8_BYTES; + break; + case 12: + cmd_sts |= MAC_HDR_EXTRA_4_BYTES; + cmd_sts |= MAC_HDR_EXTRA_8_BYTES; + break; + default: + if (net_ratelimit()) + dev_printk(KERN_ERR, &txq_to_mp(txq)->dev->dev, + "mac header length is %d?!\n", mac_hdr_len); + break; + } + switch (ip_hdr(skb)->protocol) { case IPPROTO_UDP: cmd_sts |= UDP_FRAME; @@ -2565,6 +2591,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) * have to map the buffers to ISA memory which is only 16 MB */ dev->features = NETIF_F_SG | NETIF_F_IP_CSUM; + dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM; #endif SET_NETDEV_DEV(dev, &pdev->dev); -- cgit v1.2.3 From ac0a2d0c8ab18045ab217339a71e76c76e186ede Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 15 Jul 2008 12:26:16 +0200 Subject: mv643xx_eth: bump version to 1.2 Signed-off-by: Lennert Buytenhek --- drivers/net/mv643xx_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 88bb1f1e806..46819af3b06 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -55,7 +55,7 @@ #include static char mv643xx_eth_driver_name[] = "mv643xx_eth"; -static char mv643xx_eth_driver_version[] = "1.1"; +static char mv643xx_eth_driver_version[] = "1.2"; #define MV643XX_ETH_CHECKSUM_OFFLOAD_TX #define MV643XX_ETH_NAPI -- cgit v1.2.3 From 4c7827eec78abe6fe68fd29305806467f2a51e63 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 7 Jul 2008 20:04:29 -0300 Subject: V4L/DVB (8234a): uvcvideo: Fix build for uvc input Fix a bug introduced by some trouble on my -git tree that resulted on a hunk to be lost (probably caused by some rebase). Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index f606d2951fd..2a747db6dc3 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -806,13 +806,7 @@ menuconfig V4L_USB_DRIVERS if V4L_USB_DRIVERS && USB -config USB_VIDEO_CLASS - tristate "USB Video Class (UVC)" - ---help--- - Support for the USB Video Class (UVC). Currently only video - input devices, such as webcams, are supported. - - For more information see: +source "drivers/media/video/uvc/Kconfig" source "drivers/media/video/gspca/Kconfig" -- cgit v1.2.3 From e5b13acf563e98ffc5dea8bebf80299a2a4ea088 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 24 Jul 2008 14:37:55 -0300 Subject: V4L/DVB (8451): dw2102: fix in-kernel compilation Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.h b/drivers/media/dvb/dvb-usb/dw2102.h index cb5873752e4..7a310f90683 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.h +++ b/drivers/media/dvb/dvb-usb/dw2102.h @@ -2,7 +2,7 @@ #define _DW2102_H_ #define DVB_USB_LOG_PREFIX "dw2102" -#include +#include "dvb-usb.h" extern int dvb_usb_dw2102_debug; #define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args) -- cgit v1.2.3 From 3f07af494dfa6de43137dae430431c9fbf929c0c Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 25 Jul 2008 22:25:13 -0400 Subject: of: adapt of_find_i2c_driver() to be usable by SPI also SPI has a similar problem as I2C in that it needs to determine an appropriate modalias value for each device node. This patch adapts the of_i2c of_find_i2c_driver() function to be usable by of_spi also. Signed-off-by: Grant Likely --- drivers/of/base.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/of/of_i2c.c | 64 ++------------------------------------ 2 files changed, 91 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index 23ffb7c0caf..ad8ac1a8af2 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -385,3 +385,91 @@ struct device_node *of_find_matching_node(struct device_node *from, return np; } EXPORT_SYMBOL(of_find_matching_node); + +/** + * of_modalias_table: Table of explicit compatible ==> modalias mappings + * + * This table allows particulare compatible property values to be mapped + * to modalias strings. This is useful for busses which do not directly + * understand the OF device tree but are populated based on data contained + * within the device tree. SPI and I2C are the two current users of this + * table. + * + * In most cases, devices do not need to be listed in this table because + * the modalias value can be derived directly from the compatible table. + * However, if for any reason a value cannot be derived, then this table + * provides a method to override the implicit derivation. + * + * At the moment, a single table is used for all bus types because it is + * assumed that the data size is small and that the compatible values + * should already be distinct enough to differentiate between SPI, I2C + * and other devices. + */ +struct of_modalias_table { + char *of_device; + char *modalias; +}; +static struct of_modalias_table of_modalias_table[] = { + /* Empty for now; add entries as needed */ +}; + +/** + * of_modalias_node - Lookup appropriate modalias for a device node + * @node: pointer to a device tree node + * @modalias: Pointer to buffer that modalias value will be copied into + * @len: Length of modalias value + * + * Based on the value of the compatible property, this routine will determine + * an appropriate modalias value for a particular device tree node. Three + * separate methods are used to derive a modalias value. + * + * First method is to lookup the compatible value in of_modalias_table. + * Second is to look for a "linux," entry in the compatible list + * and used that for modalias. Third is to strip off the manufacturer + * prefix from the first compatible entry and use the remainder as modalias + * + * This routine returns 0 on success + */ +int of_modalias_node(struct device_node *node, char *modalias, int len) +{ + int i, cplen; + const char *compatible; + const char *p; + + /* 1. search for exception list entry */ + for (i = 0; i < ARRAY_SIZE(of_modalias_table); i++) { + compatible = of_modalias_table[i].of_device; + if (!of_device_is_compatible(node, compatible)) + continue; + strlcpy(modalias, of_modalias_table[i].modalias, len); + return 0; + } + + compatible = of_get_property(node, "compatible", &cplen); + if (!compatible) + return -ENODEV; + + /* 2. search for linux, entry */ + p = compatible; + while (cplen > 0) { + if (!strncmp(p, "linux,", 6)) { + p += 6; + strlcpy(modalias, p, len); + return 0; + } + + i = strlen(p) + 1; + p += i; + cplen -= i; + } + + /* 3. take first compatible entry and strip manufacturer */ + p = strchr(compatible, ','); + if (!p) + return -ENODEV; + p++; + strlcpy(modalias, p, len); + return 0; +} +EXPORT_SYMBOL_GPL(of_modalias_node); + diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c index 344e1b03dd8..6a98dc8aa30 100644 --- a/drivers/of/of_i2c.c +++ b/drivers/of/of_i2c.c @@ -16,62 +16,6 @@ #include #include -struct i2c_driver_device { - char *of_device; - char *i2c_type; -}; - -static struct i2c_driver_device i2c_devices[] = { -}; - -static int of_find_i2c_driver(struct device_node *node, - struct i2c_board_info *info) -{ - int i, cplen; - const char *compatible; - const char *p; - - /* 1. search for exception list entry */ - for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) { - if (!of_device_is_compatible(node, i2c_devices[i].of_device)) - continue; - if (strlcpy(info->type, i2c_devices[i].i2c_type, - I2C_NAME_SIZE) >= I2C_NAME_SIZE) - return -ENOMEM; - - return 0; - } - - compatible = of_get_property(node, "compatible", &cplen); - if (!compatible) - return -ENODEV; - - /* 2. search for linux, entry */ - p = compatible; - while (cplen > 0) { - if (!strncmp(p, "linux,", 6)) { - p += 6; - if (strlcpy(info->type, p, - I2C_NAME_SIZE) >= I2C_NAME_SIZE) - return -ENOMEM; - return 0; - } - - i = strlen(p) + 1; - p += i; - cplen -= i; - } - - /* 3. take fist compatible entry and strip manufacturer */ - p = strchr(compatible, ','); - if (!p) - return -ENODEV; - p++; - if (strlcpy(info->type, p, I2C_NAME_SIZE) >= I2C_NAME_SIZE) - return -ENOMEM; - return 0; -} - void of_register_i2c_devices(struct i2c_adapter *adap, struct device_node *adap_node) { @@ -83,6 +27,9 @@ void of_register_i2c_devices(struct i2c_adapter *adap, const u32 *addr; int len; + if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) + continue; + addr = of_get_property(node, "reg", &len); if (!addr || len < sizeof(int) || *addr > (1 << 10) - 1) { printk(KERN_ERR @@ -92,11 +39,6 @@ void of_register_i2c_devices(struct i2c_adapter *adap, info.irq = irq_of_parse_and_map(node, 0); - if (of_find_i2c_driver(node, &info) < 0) { - irq_dispose_mapping(info.irq); - continue; - } - info.addr = *addr; request_module(info.type); -- cgit v1.2.3 From dc87c98e8f635a718f1abb2c3e15fc77c0001651 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 15 May 2008 16:50:22 -0600 Subject: spi: split up spi_new_device() to allow two stage registration. spi_new_device() allocates and registers an spi device all in one swoop. If the driver needs to add extra data to the spi_device before it is registered, then this causes problems. This is needed for OF device tree support so that the SPI device tree helper can add a pointer to the device node after the device is allocated, but before the device is registered. OF aware SPI devices can then retrieve data out of the device node to populate a platform data structure. This patch splits the allocation and registration portions of code out of spi_new_device() and creates two new functions; spi_alloc_device() and spi_register_device(). spi_new_device() is modified to use the new functions for allocation and registration. None of the existing users of spi_new_device() should be affected by this change. Drivers using the new API can forego the use of spi_board_info structure to describe the device layout and populate data into the spi_device structure directly. This change is in preparation for adding an OF device tree parser to generate spi_devices based on data in the device tree. Signed-off-by: Grant Likely Acked-by: David Brownell --- drivers/spi/spi.c | 139 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 95 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index ecca4a6a6f9..964124b60db 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -178,6 +178,96 @@ struct boardinfo { static LIST_HEAD(board_list); static DEFINE_MUTEX(board_lock); +/** + * spi_alloc_device - Allocate a new SPI device + * @master: Controller to which device is connected + * Context: can sleep + * + * Allows a driver to allocate and initialize a spi_device without + * registering it immediately. This allows a driver to directly + * fill the spi_device with device parameters before calling + * spi_add_device() on it. + * + * Caller is responsible to call spi_add_device() on the returned + * spi_device structure to add it to the SPI master. If the caller + * needs to discard the spi_device without adding it, then it should + * call spi_dev_put() on it. + * + * Returns a pointer to the new device, or NULL. + */ +struct spi_device *spi_alloc_device(struct spi_master *master) +{ + struct spi_device *spi; + struct device *dev = master->dev.parent; + + if (!spi_master_get(master)) + return NULL; + + spi = kzalloc(sizeof *spi, GFP_KERNEL); + if (!spi) { + dev_err(dev, "cannot alloc spi_device\n"); + spi_master_put(master); + return NULL; + } + + spi->master = master; + spi->dev.parent = dev; + spi->dev.bus = &spi_bus_type; + spi->dev.release = spidev_release; + device_initialize(&spi->dev); + return spi; +} +EXPORT_SYMBOL_GPL(spi_alloc_device); + +/** + * spi_add_device - Add spi_device allocated with spi_alloc_device + * @spi: spi_device to register + * + * Companion function to spi_alloc_device. Devices allocated with + * spi_alloc_device can be added onto the spi bus with this function. + * + * Returns 0 on success; non-zero on failure + */ +int spi_add_device(struct spi_device *spi) +{ + struct device *dev = spi->master->dev.parent; + int status; + + /* Chipselects are numbered 0..max; validate. */ + if (spi->chip_select >= spi->master->num_chipselect) { + dev_err(dev, "cs%d >= max %d\n", + spi->chip_select, + spi->master->num_chipselect); + return -EINVAL; + } + + /* Set the bus ID string */ + snprintf(spi->dev.bus_id, sizeof spi->dev.bus_id, + "%s.%u", spi->master->dev.bus_id, + spi->chip_select); + + /* drivers may modify this initial i/o setup */ + status = spi->master->setup(spi); + if (status < 0) { + dev_err(dev, "can't %s %s, status %d\n", + "setup", spi->dev.bus_id, status); + return status; + } + + /* driver core catches callers that misbehave by defining + * devices that already exist. + */ + status = device_add(&spi->dev); + if (status < 0) { + dev_err(dev, "can't %s %s, status %d\n", + "add", spi->dev.bus_id, status); + return status; + } + + dev_dbg(dev, "registered child %s\n", spi->dev.bus_id); + return 0; +} +EXPORT_SYMBOL_GPL(spi_add_device); /** * spi_new_device - instantiate one new SPI device @@ -197,7 +287,6 @@ struct spi_device *spi_new_device(struct spi_master *master, struct spi_board_info *chip) { struct spi_device *proxy; - struct device *dev = master->dev.parent; int status; /* NOTE: caller did any chip->bus_num checks necessary. @@ -207,66 +296,28 @@ struct spi_device *spi_new_device(struct spi_master *master, * suggests syslogged diagnostics are best here (ugh). */ - /* Chipselects are numbered 0..max; validate. */ - if (chip->chip_select >= master->num_chipselect) { - dev_err(dev, "cs%d > max %d\n", - chip->chip_select, - master->num_chipselect); - return NULL; - } - - if (!spi_master_get(master)) + proxy = spi_alloc_device(master); + if (!proxy) return NULL; WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias)); - proxy = kzalloc(sizeof *proxy, GFP_KERNEL); - if (!proxy) { - dev_err(dev, "can't alloc dev for cs%d\n", - chip->chip_select); - goto fail; - } - proxy->master = master; proxy->chip_select = chip->chip_select; proxy->max_speed_hz = chip->max_speed_hz; proxy->mode = chip->mode; proxy->irq = chip->irq; strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias)); - - snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id, - "%s.%u", master->dev.bus_id, - chip->chip_select); - proxy->dev.parent = dev; - proxy->dev.bus = &spi_bus_type; proxy->dev.platform_data = (void *) chip->platform_data; proxy->controller_data = chip->controller_data; proxy->controller_state = NULL; - proxy->dev.release = spidev_release; - /* drivers may modify this initial i/o setup */ - status = master->setup(proxy); + status = spi_add_device(proxy); if (status < 0) { - dev_err(dev, "can't %s %s, status %d\n", - "setup", proxy->dev.bus_id, status); - goto fail; + spi_dev_put(proxy); + return NULL; } - /* driver core catches callers that misbehave by defining - * devices that already exist. - */ - status = device_register(&proxy->dev); - if (status < 0) { - dev_err(dev, "can't %s %s, status %d\n", - "add", proxy->dev.bus_id, status); - goto fail; - } - dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id); return proxy; - -fail: - spi_master_put(master); - kfree(proxy); - return NULL; } EXPORT_SYMBOL_GPL(spi_new_device); -- cgit v1.2.3 From 284b01897340974000bcc84de87a4e1becc8a83d Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 16 May 2008 11:37:09 -0600 Subject: spi: Add OF binding support for SPI busses This patch adds support for populating an SPI bus based on data in the OF device tree. This is useful for powerpc platforms which use the device tree instead of discrete code for describing platform layout. Signed-off-by: Grant Likely --- drivers/of/Kconfig | 6 ++++ drivers/of/Makefile | 1 + drivers/of/of_spi.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 drivers/of/of_spi.c (limited to 'drivers') diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 1d7ec312934..f821dbc952a 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -13,3 +13,9 @@ config OF_I2C depends on PPC_OF && I2C help OpenFirmware I2C accessors + +config OF_SPI + def_tristate SPI + depends on OF && PPC_OF && SPI + help + OpenFirmware SPI accessors diff --git a/drivers/of/Makefile b/drivers/of/Makefile index 548772e871f..4c3c6f8e36f 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -2,3 +2,4 @@ obj-y = base.o obj-$(CONFIG_OF_DEVICE) += device.o platform.o obj-$(CONFIG_OF_GPIO) += gpio.o obj-$(CONFIG_OF_I2C) += of_i2c.o +obj-$(CONFIG_OF_SPI) += of_spi.o diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c new file mode 100644 index 00000000000..b01eec026f6 --- /dev/null +++ b/drivers/of/of_spi.c @@ -0,0 +1,93 @@ +/* + * SPI OF support routines + * Copyright (C) 2008 Secret Lab Technologies Ltd. + * + * Support routines for deriving SPI device attachments from the device + * tree. + */ + +#include +#include +#include +#include + +/** + * of_register_spi_devices - Register child devices onto the SPI bus + * @master: Pointer to spi_master device + * @np: parent node of SPI device nodes + * + * Registers an spi_device for each child node of 'np' which has a 'reg' + * property. + */ +void of_register_spi_devices(struct spi_master *master, struct device_node *np) +{ + struct spi_device *spi; + struct device_node *nc; + const u32 *prop; + int rc; + int len; + + for_each_child_of_node(np, nc) { + /* Alloc an spi_device */ + spi = spi_alloc_device(master); + if (!spi) { + dev_err(&master->dev, "spi_device alloc error for %s\n", + nc->full_name); + spi_dev_put(spi); + continue; + } + + /* Select device driver */ + if (of_modalias_node(nc, spi->modalias, + sizeof(spi->modalias)) < 0) { + dev_err(&master->dev, "cannot find modalias for %s\n", + nc->full_name); + spi_dev_put(spi); + continue; + } + + /* Device address */ + prop = of_get_property(nc, "reg", &len); + if (!prop || len < sizeof(*prop)) { + dev_err(&master->dev, "%s has no 'reg' property\n", + nc->full_name); + spi_dev_put(spi); + continue; + } + spi->chip_select = *prop; + + /* Mode (clock phase/polarity/etc.) */ + if (of_find_property(nc, "spi-cpha", NULL)) + spi->mode |= SPI_CPHA; + if (of_find_property(nc, "spi-cpol", NULL)) + spi->mode |= SPI_CPOL; + + /* Device speed */ + prop = of_get_property(nc, "spi-max-frequency", &len); + if (!prop || len < sizeof(*prop)) { + dev_err(&master->dev, "%s has no 'spi-max-frequency' property\n", + nc->full_name); + spi_dev_put(spi); + continue; + } + spi->max_speed_hz = *prop; + + /* IRQ */ + spi->irq = irq_of_parse_and_map(nc, 0); + + /* Store a pointer to the node in the device structure */ + of_node_get(nc); + spi->dev.archdata.of_node = nc; + + /* Register the new device */ + request_module(spi->modalias); + rc = spi_add_device(spi); + if (rc) { + dev_err(&master->dev, "spi_device register error %s\n", + nc->full_name); + spi_dev_put(spi); + } + + } +} +EXPORT_SYMBOL(of_register_spi_devices); -- cgit v1.2.3 From 0bc3cc03fa6e1c20aecb5a33356bcaae410640b9 Mon Sep 17 00:00:00 2001 From: Mike Travis Date: Thu, 24 Jul 2008 18:21:31 -0700 Subject: cpumask: change cpumask_of_cpu_ptr to use new cpumask_of_cpu * Replace previous instances of the cpumask_of_cpu_ptr* macros with a the new (lvalue capable) generic cpumask_of_cpu(). Signed-off-by: Mike Travis Cc: Andrew Morton Cc: Jack Steiner Cc: Rusty Russell Signed-off-by: Ingo Molnar --- drivers/acpi/processor_throttling.c | 11 +++-------- drivers/firmware/dcdbas.c | 3 +-- drivers/misc/sgi-xp/xpc_main.c | 3 +-- 3 files changed, 5 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index a2c3f9cfa54..a56fc6c4394 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -827,7 +827,6 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr) static int acpi_processor_get_throttling(struct acpi_processor *pr) { cpumask_t saved_mask; - cpumask_of_cpu_ptr_declare(new_mask); int ret; if (!pr) @@ -839,8 +838,7 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr) * Migrate task to the cpu pointed by pr. */ saved_mask = current->cpus_allowed; - cpumask_of_cpu_ptr_next(new_mask, pr->id); - set_cpus_allowed_ptr(current, new_mask); + set_cpus_allowed_ptr(current, &cpumask_of_cpu(pr->id)); ret = pr->throttling.acpi_processor_get_throttling(pr); /* restore the previous state */ set_cpus_allowed_ptr(current, &saved_mask); @@ -989,7 +987,6 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr, int acpi_processor_set_throttling(struct acpi_processor *pr, int state) { cpumask_t saved_mask; - cpumask_of_cpu_ptr_declare(new_mask); int ret = 0; unsigned int i; struct acpi_processor *match_pr; @@ -1028,8 +1025,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state) * it can be called only for the cpu pointed by pr. */ if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) { - cpumask_of_cpu_ptr_next(new_mask, pr->id); - set_cpus_allowed_ptr(current, new_mask); + set_cpus_allowed_ptr(current, &cpumask_of_cpu(pr->id)); ret = p_throttling->acpi_processor_set_throttling(pr, t_state.target_state); } else { @@ -1060,8 +1056,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state) continue; } t_state.cpu = i; - cpumask_of_cpu_ptr_next(new_mask, i); - set_cpus_allowed_ptr(current, new_mask); + set_cpus_allowed_ptr(current, &cpumask_of_cpu(i)); ret = match_pr->throttling. acpi_processor_set_throttling( match_pr, t_state.target_state); diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index c66817e7717..50a071f1c94 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c @@ -245,7 +245,6 @@ static ssize_t host_control_on_shutdown_store(struct device *dev, static int smi_request(struct smi_cmd *smi_cmd) { cpumask_t old_mask; - cpumask_of_cpu_ptr(new_mask, 0); int ret = 0; if (smi_cmd->magic != SMI_CMD_MAGIC) { @@ -256,7 +255,7 @@ static int smi_request(struct smi_cmd *smi_cmd) /* SMI requires CPU 0 */ old_mask = current->cpus_allowed; - set_cpus_allowed_ptr(current, new_mask); + set_cpus_allowed_ptr(current, &cpumask_of_cpu(0)); if (smp_processor_id() != 0) { dev_dbg(&dcdbas_pdev->dev, "%s: failed to get CPU 0\n", __func__); diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index 579b01ff82d..c3b4227f48a 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -229,11 +229,10 @@ xpc_hb_checker(void *ignore) int last_IRQ_count = 0; int new_IRQ_count; int force_IRQ = 0; - cpumask_of_cpu_ptr(cpumask, XPC_HB_CHECK_CPU); /* this thread was marked active by xpc_hb_init() */ - set_cpus_allowed_ptr(current, cpumask); + set_cpus_allowed_ptr(current, &cpumask_of_cpu(XPC_HB_CHECK_CPU)); /* set our heartbeating to other partitions into motion */ xpc_hb_check_timeout = jiffies + (xpc_hb_check_interval * HZ); -- cgit v1.2.3 From c5e0bd1a982ee449b3598600f85895dc3bc8c13f Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 21 Jul 2008 23:17:36 -0300 Subject: V4L/DVB (8453): sms1xxx: dvb/siano/: cleanups This patch contains the following cleanups: - mark smscore_module_init() as __init - mark smscore_module_exit as __exit - make the following needlessly global code static: - smscoreapi.c: struct g_smscore_notifyees - smscoreapi.c: struct g_smscore_devices - smscoreapi.c: struct g_smscore_deviceslock - smscoreapi.c: struct g_smscore_registry - smscoreapi.c: struct g_smscore_registrylock - smscoreapi.c: smscore_module_init() - smscoreapi.c: smscore_module_exit() - smsdvb.c: struct g_smsdvb_clients - smsdvb.c: struct g_smsdvb_clientslock Signed-off-by: Adrian Bunk Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/siano/smscoreapi.c | 14 +++++++------- drivers/media/dvb/siano/smsdvb.c | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c index b4b8ed795c9..c5f45fed69d 100644 --- a/drivers/media/dvb/siano/smscoreapi.c +++ b/drivers/media/dvb/siano/smscoreapi.c @@ -110,12 +110,12 @@ struct smscore_registry_entry_t { enum sms_device_type_st type; }; -struct list_head g_smscore_notifyees; -struct list_head g_smscore_devices; -struct mutex g_smscore_deviceslock; +static struct list_head g_smscore_notifyees; +static struct list_head g_smscore_devices; +static struct mutex g_smscore_deviceslock; -struct list_head g_smscore_registry; -struct mutex g_smscore_registrylock; +static struct list_head g_smscore_registry; +static struct mutex g_smscore_registrylock; static int default_mode = 4; @@ -1187,7 +1187,7 @@ int smsclient_sendrequest(struct smscore_client_t *client, } -int smscore_module_init(void) +static int __init smscore_module_init(void) { int rc = 0; @@ -1209,7 +1209,7 @@ int smscore_module_init(void) return rc; } -void smscore_module_exit(void) +static void __exit smscore_module_exit(void) { kmutex_lock(&g_smscore_deviceslock); diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c index 6f9c1856386..229274a1411 100644 --- a/drivers/media/dvb/siano/smsdvb.c +++ b/drivers/media/dvb/siano/smsdvb.c @@ -27,8 +27,8 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -struct list_head g_smsdvb_clients; -struct mutex g_smsdvb_clientslock; +static struct list_head g_smsdvb_clients; +static struct mutex g_smsdvb_clientslock; static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) { -- cgit v1.2.3 From 6af492e56648e786e0dfb84d538fb7f9ecc02504 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 22 Jul 2008 07:09:33 -0300 Subject: V4L/DVB (8455): gspca_sonixb sn9c103 + ov7630 autoexposure and cleanup Andoni Zubimendi has been doing some testing with his sn9c103 cam with ov7630 sensor, and with this patch the exposure setting and autoexposure now work. This patch also removes some special cases in the shared ov6650 / ov7630 code which now are handled the same for both sensors and it adds a new special case which stops us from changing the hsync / vsync polarity settings from their default on the ov7630 (which we were doing as a side-effect of using the ov6650 exposure code for the ov7630). Last this patch removes the superficial difference between the OV7630 and OV7630_3 sensors. Signed-off-by: Andoni Zubimendi Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixb.c | 174 +++++++++++++++++-------------------- 1 file changed, 82 insertions(+), 92 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index f6bef896d3a..4f9c9ecb06e 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -41,6 +41,7 @@ struct sd { unsigned char brightness; unsigned char autogain; unsigned char autogain_ignore_frames; + unsigned char frames_to_drop; unsigned char freq; /* light freq filter setting */ unsigned char saturation; unsigned char hue; @@ -51,13 +52,13 @@ struct sd { #define SENSOR_HV7131R 0 #define SENSOR_OV6650 1 #define SENSOR_OV7630 2 -#define SENSOR_OV7630_3 3 -#define SENSOR_PAS106 4 -#define SENSOR_PAS202 5 -#define SENSOR_TAS5110 6 -#define SENSOR_TAS5130CXX 7 +#define SENSOR_PAS106 3 +#define SENSOR_PAS202 4 +#define SENSOR_TAS5110 5 +#define SENSOR_TAS5130CXX 6 char sensor_has_gain; __u8 sensor_addr; + __u8 reg11; }; #define COMP2 0x8f @@ -318,7 +319,7 @@ static const __u8 initOv7630_3[] = { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */ 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */ }; -static const __u8 ov7630_sensor_init_com[][8] = { +static const __u8 ov7630_sensor_init[][8] = { {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10}, /* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */ @@ -339,17 +340,6 @@ static const __u8 ov7630_sensor_init_com[][8] = { {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10}, {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10}, }; -static const __u8 ov7630_sensor_init[][8] = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */ - {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10}, /* jfm */ - {0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16}, - {0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16}, - {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */ -}; -static const __u8 ov7630_sensor_init_3[][8] = { - {0xa0, 0x21, 0x2a, 0xa0, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x2a, 0x80, 0x00, 0x00, 0x00, 0x10}, -}; static const __u8 initPas106[] = { 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00, @@ -539,7 +529,6 @@ static void setbrightness(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_OV6650: - case SENSOR_OV7630_3: case SENSOR_OV7630: { __u8 i2cOV[] = {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10}; @@ -632,7 +621,7 @@ static void setsensorgain(struct gspca_dev *gspca_dev) case SENSOR_OV6650: gain >>= 1; /* fall thru */ - case SENSOR_OV7630_3: { + case SENSOR_OV7630: { __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; i2c[1] = sd->sensor_addr; @@ -687,7 +676,7 @@ static void setexposure(struct gspca_dev *gspca_dev) break; } case SENSOR_OV6650: - case SENSOR_OV7630_3: { + case SENSOR_OV7630: { /* The ov6650 / ov7630 have 2 registers which both influence exposure, register 11, whose low nibble sets the nr off fps according to: fps = 30 / (low_nibble + 1) @@ -702,16 +691,20 @@ static void setexposure(struct gspca_dev *gspca_dev) The code maps our 0 - 510 ms exposure ctrl to these 2 registers, trying to keep fps as high as possible. */ - __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10}; - int reg10, reg11; + __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10}; + int reg10, reg11, reg10_max; + /* ov6645 datasheet says reg10_max is 9a, but that uses tline * 2 * reg10 as formula for calculating texpo, the ov6650 probably uses the same formula as the 7730 which uses tline * 4 * reg10, which explains why the reg10max we've found experimentally for the ov6650 is exactly half that of the ov6645. The ov7630 datasheet says the max is 0x41. */ - const int reg10_max = (sd->sensor == SENSOR_OV6650) - ? 0x4d : 0x41; + if (sd->sensor == SENSOR_OV6650) { + reg10_max = 0x4d; + i2c[4] = 0xc0; /* OV6650 needs non default vsync pol */ + } else + reg10_max = 0x41; reg11 = (60 * sd->exposure + 999) / 1000; if (reg11 < 1) @@ -732,20 +725,23 @@ static void setexposure(struct gspca_dev *gspca_dev) else if (reg10 > reg10_max) reg10 = reg10_max; + /* In 640x480, if the reg11 has less than 3, the image is + unstable (not enough bandwidth). */ + if (gspca_dev->width == 640 && reg11 < 3) + reg11 = 3; + /* Write reg 10 and reg11 low nibble */ i2c[1] = sd->sensor_addr; i2c[3] = reg10; i2c[4] |= reg11 - 1; - if (sd->sensor == SENSOR_OV7630_3) { - __u8 reg76 = reg10 & 0x03; - __u8 i2c_reg76[] = {0xa0, 0x21, 0x76, 0x00, - 0x00, 0x00, 0x00, 0x10}; - reg10 >>= 2; - i2c_reg76[3] = reg76; - if (i2c_w(gspca_dev, i2c_reg76) < 0) - PDEBUG(D_ERR, "i2c error exposure"); - } - if (i2c_w(gspca_dev, i2c) < 0) + + /* If register 11 didn't change, don't change it */ + if (sd->reg11 == reg11 ) + i2c[0] = 0xa0; + + if (i2c_w(gspca_dev, i2c) == 0) + sd->reg11 = reg11; + else PDEBUG(D_ERR, "i2c error exposure"); break; } @@ -758,11 +754,11 @@ static void setfreq(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_OV6650: - case SENSOR_OV7630_3: { + case SENSOR_OV7630: { /* Framerate adjust register for artificial light 50 hz flicker - compensation, identical to ov6630 0x2b register, see ov6630 - datasheet. - 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */ + compensation, for the ov6650 this is identical to ov6630 + 0x2b register, see ov6630 datasheet. + 0x4f / 0x8a -> (30 fps -> 25 fps), 0x00 -> no adjustment */ __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}; switch (sd->freq) { default: @@ -789,7 +785,6 @@ static void setsaturation(struct gspca_dev *gspca_dev) switch (sd->sensor) { /* case SENSOR_OV6650: */ - case SENSOR_OV7630_3: case SENSOR_OV7630: { __u8 i2c[] = {0xa0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}; i2c[1] = sd->sensor_addr; @@ -810,7 +805,6 @@ static void sethue(struct gspca_dev *gspca_dev) switch (sd->sensor) { /* case SENSOR_OV6650: */ - case SENSOR_OV7630_3: case SENSOR_OV7630: { __u8 i2c[] = {0xa0, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10}; i2c[1] = sd->sensor_addr; @@ -830,7 +824,6 @@ static void setcontrast(struct gspca_dev *gspca_dev) switch (sd->sensor) { /* case SENSOR_OV6650: */ - case SENSOR_OV7630_3: case SENSOR_OV7630: { __u8 i2c[] = {0xa0, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10}; i2c[1] = sd->sensor_addr; @@ -880,8 +873,6 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->fr_h_sz = 12; /* default size of the frame header */ sd->sd_desc.nctrls = 2; /* default nb of ctrls */ - sd->autogain = AUTOGAIN_DEF; /* default is autogain active */ - product = id->idProduct; /* switch (id->idVendor) { */ /* case 0x0c45: * Sonix */ @@ -912,17 +903,14 @@ static int sd_config(struct gspca_dev *gspca_dev, case 0x6019: /* SN9C101 */ case 0x602c: /* SN9C102 */ case 0x602e: /* SN9C102 */ - sd->sensor = SENSOR_OV7630; - sd->sensor_addr = 0x21; - break; case 0x60b0: /* SN9C103 */ - sd->sensor = SENSOR_OV7630_3; + sd->sensor = SENSOR_OV7630; sd->sensor_addr = 0x21; - sd->fr_h_sz = 18; /* size of frame header */ sd->sensor_has_gain = 1; - sd->sd_desc.nctrls = 8; + sd->sd_desc.nctrls = 5; sd->sd_desc.dq_callback = do_autogain; - sd->autogain = 0; + if (product == 0x60b0) + sd->fr_h_sz = 18; /* size of frame header */ break; case 0x6024: /* SN9C102 */ case 0x6025: /* SN9C102 */ @@ -948,7 +936,7 @@ static int sd_config(struct gspca_dev *gspca_dev, if (!sif) { cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); - if (sd->sensor == SENSOR_OV7630_3) { + if (product == 0x60b0) { /* SN9C103 with OV7630 */ /* We only have 320x240 & 640x480 */ cam->cam_mode++; cam->nmodes--; @@ -960,12 +948,15 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->brightness = BRIGHTNESS_DEF; sd->gain = GAIN_DEF; sd->exposure = EXPOSURE_DEF; + sd->autogain = AUTOGAIN_DEF; sd->freq = FREQ_DEF; sd->contrast = CONTRAST_DEF; sd->saturation = SATURATION_DEF; sd->hue = HUE_DEF; - if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */ + + if (product == 0x60b0) /* SN9C103 with OV7630 */ reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630); + return 0; } @@ -999,7 +990,7 @@ static void pas106_i2cinit(struct gspca_dev *gspca_dev) static void sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int mode, l; + int mode, l = 0x1f; const __u8 *sn9c10x; __u8 reg01, reg17; __u8 reg17_19[3]; @@ -1019,13 +1010,11 @@ static void sd_start(struct gspca_dev *gspca_dev) reg17_19[2] = 0x20; break; case SENSOR_OV7630: - sn9c10x = initOv7630; - reg17_19[0] = 0x68; - reg17_19[1] = (mode << 4) | COMP2; - reg17_19[2] = MCK_INIT1; - break; - case SENSOR_OV7630_3: - sn9c10x = initOv7630_3; + if (sd->fr_h_sz == 18) { /* SN9C103 */ + sn9c10x = initOv7630_3; + l = sizeof initOv7630_3; + } else + sn9c10x = initOv7630; reg17_19[0] = 0x68; reg17_19[1] = (mode << 4) | COMP2; reg17_19[2] = MCK_INIT1; @@ -1056,30 +1045,22 @@ static void sd_start(struct gspca_dev *gspca_dev) reg17_19[2] = mode ? 0x23 : 0x43; break; } - switch (sd->sensor) { - case SENSOR_OV7630: + + /* Special case for SN9C101/2 with OV 7630 */ + /* HDG: is this really necessary we overwrite the values immediately + afterwards with the ones from the template ?? */ + if (sd->sensor == SENSOR_OV7630 && sd->fr_h_sz == 12) { reg01 = 0x06; reg17 = 0x29; - l = sizeof initOv7630; - break; - case SENSOR_OV7630_3: - reg01 = 0x44; - reg17 = 0x68; - l = sizeof initOv7630_3; - break; - default: + } else { reg01 = sn9c10x[0]; reg17 = sn9c10x[0x17 - 1]; - l = 0x1f; - break; } /* reg 0x01 bit 2 video transfert on */ reg_w(gspca_dev, 0x01, ®01, 1); /* reg 0x17 SensorClk enable inv Clk 0x60 */ reg_w(gspca_dev, 0x17, ®17, 1); -/*fixme: for ov7630 102 - reg_w(gspca_dev, 0x01, {0x06, sn9c10x[1]}, 2); */ /* Set the registers from the template */ reg_w_big(gspca_dev, 0x01, sn9c10x, l); switch (sd->sensor) { @@ -1092,17 +1073,13 @@ static void sd_start(struct gspca_dev *gspca_dev) sizeof ov6650_sensor_init); break; case SENSOR_OV7630: - i2c_w_vector(gspca_dev, ov7630_sensor_init_com, - sizeof ov7630_sensor_init_com); - msleep(200); i2c_w_vector(gspca_dev, ov7630_sensor_init, sizeof ov7630_sensor_init); - break; - case SENSOR_OV7630_3: - i2c_w_vector(gspca_dev, ov7630_sensor_init_com, - sizeof ov7630_sensor_init_com); - msleep(200); - i2c_w(gspca_dev, ov7630_sensor_init_3[mode]); + if (sd->fr_h_sz == 18) { /* SN9C103 */ + const __u8 i2c[] = { 0xa0, 0x21, 0x13, 0x80, 0x00, + 0x00, 0x00, 0x10 }; + i2c_w(gspca_dev, i2c); + } break; case SENSOR_PAS106: pas106_i2cinit(gspca_dev); @@ -1142,6 +1119,8 @@ static void sd_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x18, ®17_19[1], 2); msleep(20); + sd->reg11 = -1; + setgain(gspca_dev); setbrightness(gspca_dev); setexposure(gspca_dev); @@ -1150,6 +1129,7 @@ static void sd_start(struct gspca_dev *gspca_dev) sethue(gspca_dev); setcontrast(gspca_dev); + sd->frames_to_drop = 0; sd->autogain_ignore_frames = 0; atomic_set(&sd->avg_lum, -1); } @@ -1195,21 +1175,31 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, && data[3 + i] == 0xc4 && data[4 + i] == 0xc4 && data[5 + i] == 0x96) { /* start of frame */ - frame = gspca_frame_add(gspca_dev, LAST_PACKET, - frame, data, 0); + int lum = -1; + int pkt_type = LAST_PACKET; + if (len - i < sd->fr_h_sz) { - atomic_set(&sd->avg_lum, -1); PDEBUG(D_STREAM, "packet too short to" " get avg brightness"); } else if (sd->fr_h_sz == 12) { - atomic_set(&sd->avg_lum, - data[i + 8] + - (data[i + 9] << 8)); + lum = data[i + 8] + (data[i + 9] << 8); } else { - atomic_set(&sd->avg_lum, - data[i + 9] + - (data[i + 10] << 8)); + lum = data[i + 9] + + (data[i + 10] << 8); } + if (lum == 0) { + lum = -1; + sd->frames_to_drop = 2; + } + atomic_set(&sd->avg_lum, lum); + + if (sd->frames_to_drop) { + sd->frames_to_drop--; + pkt_type = DISCARD_PACKET; + } + + frame = gspca_frame_add(gspca_dev, pkt_type, + frame, data, 0); data += i + sd->fr_h_sz; len -= i + sd->fr_h_sz; gspca_frame_add(gspca_dev, FIRST_PACKET, -- cgit v1.2.3 From e0a33d4d6e028bf40a18069c00884671be75c6b4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 22 Jul 2008 07:13:21 -0300 Subject: V4L/DVB (8456): gspca_sonixb remove non working ovXXXX contrast, hue and saturation ctrls gspca_sonixb remove non working ovXXXX contrast, hue and saturation ctrls Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixb.c | 171 ------------------------------------- 1 file changed, 171 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 4f9c9ecb06e..f8e510cfdf9 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -43,9 +43,6 @@ struct sd { unsigned char autogain_ignore_frames; unsigned char frames_to_drop; unsigned char freq; /* light freq filter setting */ - unsigned char saturation; - unsigned char hue; - unsigned char contrast; unsigned char fr_h_sz; /* size of frame header */ char sensor; /* Type of image sensor chip */ @@ -90,12 +87,6 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val); -static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls[] = { { @@ -172,48 +163,6 @@ static struct ctrl sd_ctrls[] = { .set = sd_setfreq, .get = sd_getfreq, }, - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 255, - .step = 1, -#define SATURATION_DEF 127 - .default_value = SATURATION_DEF, - }, - .set = sd_setsaturation, - .get = sd_getsaturation, - }, - { - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = 0, - .maximum = 255, - .step = 1, -#define HUE_DEF 127 - .default_value = HUE_DEF, - }, - .set = sd_sethue, - .get = sd_gethue, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, -#define CONTRAST_DEF 127 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, }; static struct v4l2_pix_format vga_mode[] = { @@ -779,66 +728,6 @@ static void setfreq(struct gspca_dev *gspca_dev) } } -static void setsaturation(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->sensor) { -/* case SENSOR_OV6650: */ - case SENSOR_OV7630: { - __u8 i2c[] = {0xa0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}; - i2c[1] = sd->sensor_addr; - i2c[3] = sd->saturation & 0xf0; - if (i2c_w(gspca_dev, i2c) < 0) - PDEBUG(D_ERR, "i2c error setsaturation"); - else - PDEBUG(D_CONF, "saturation set to: %d", - (int)sd->saturation); - break; - } - } -} - -static void sethue(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->sensor) { -/* case SENSOR_OV6650: */ - case SENSOR_OV7630: { - __u8 i2c[] = {0xa0, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10}; - i2c[1] = sd->sensor_addr; - i2c[3] = 0x20 | (sd->hue >> 3); - if (i2c_w(gspca_dev, i2c) < 0) - PDEBUG(D_ERR, "i2c error setsaturation"); - else - PDEBUG(D_CONF, "hue set to: %d", (int)sd->hue); - break; - } - } -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->sensor) { -/* case SENSOR_OV6650: */ - case SENSOR_OV7630: { - __u8 i2c[] = {0xa0, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10}; - i2c[1] = sd->sensor_addr; - i2c[3] = 0x20 | (sd->contrast >> 3); - if (i2c_w(gspca_dev, i2c) < 0) - PDEBUG(D_ERR, "i2c error setcontrast"); - else - PDEBUG(D_CONF, "contrast set to: %d", - (int)sd->contrast); - break; - } - } -} - - static void do_autogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -950,9 +839,6 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->exposure = EXPOSURE_DEF; sd->autogain = AUTOGAIN_DEF; sd->freq = FREQ_DEF; - sd->contrast = CONTRAST_DEF; - sd->saturation = SATURATION_DEF; - sd->hue = HUE_DEF; if (product == 0x60b0) /* SN9C103 with OV7630 */ reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630); @@ -1125,9 +1011,6 @@ static void sd_start(struct gspca_dev *gspca_dev) setbrightness(gspca_dev); setexposure(gspca_dev); setfreq(gspca_dev); - setsaturation(gspca_dev); - sethue(gspca_dev); - setcontrast(gspca_dev); sd->frames_to_drop = 0; sd->autogain_ignore_frames = 0; @@ -1314,60 +1197,6 @@ static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->saturation = val; - if (gspca_dev->streaming) - setsaturation(gspca_dev); - return 0; -} - -static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->saturation; - return 0; -} - -static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hue = val; - if (gspca_dev->streaming) - sethue(gspca_dev); - return 0; -} - -static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->hue; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - static int sd_querymenu(struct gspca_dev *gspca_dev, struct v4l2_querymenu *menu) { -- cgit v1.2.3 From 84754319e30a25626f6bf0d84efc7935ba1d0b3d Mon Sep 17 00:00:00 2001 From: Andoni Zubimendi Date: Tue, 22 Jul 2008 08:39:24 -0300 Subject: V4L/DVB (8457): gspca_sonixb remove some no longer needed sn9c103+ov7630 special cases gspca_sonixb remove some no longer needed sn9c103+ov7630 special cases Signed-off-by: Andoni Zubimendi Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixb.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index f8e510cfdf9..fd91f43e078 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -195,8 +195,6 @@ static struct v4l2_pix_format sif_mode[] = { .priv = 0}, }; -static const __u8 probe_ov7630[] = {0x08, 0x44}; - static const __u8 initHv7131[] = { 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -825,11 +823,6 @@ static int sd_config(struct gspca_dev *gspca_dev, if (!sif) { cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); - if (product == 0x60b0) { /* SN9C103 with OV7630 */ - /* We only have 320x240 & 640x480 */ - cam->cam_mode++; - cam->nmodes--; - } } else { cam->cam_mode = sif_mode; cam->nmodes = ARRAY_SIZE(sif_mode); @@ -840,9 +833,6 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->autogain = AUTOGAIN_DEF; sd->freq = FREQ_DEF; - if (product == 0x60b0) /* SN9C103 with OV7630 */ - reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630); - return 0; } -- cgit v1.2.3 From fff4205f1d64163132609942314e94ec3ba2ed6b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 23 Jul 2008 07:04:39 -0300 Subject: V4L/DVB (8458): gspca_sonixb remove one more no longer needed special case from the code gspca_sonixb remove one more no longer needed special case from the code Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixb.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index fd91f43e078..93d36545659 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -868,7 +868,6 @@ static void sd_start(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; int mode, l = 0x1f; const __u8 *sn9c10x; - __u8 reg01, reg17; __u8 reg17_19[3]; mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; @@ -922,21 +921,10 @@ static void sd_start(struct gspca_dev *gspca_dev) break; } - /* Special case for SN9C101/2 with OV 7630 */ - /* HDG: is this really necessary we overwrite the values immediately - afterwards with the ones from the template ?? */ - if (sd->sensor == SENSOR_OV7630 && sd->fr_h_sz == 12) { - reg01 = 0x06; - reg17 = 0x29; - } else { - reg01 = sn9c10x[0]; - reg17 = sn9c10x[0x17 - 1]; - } - /* reg 0x01 bit 2 video transfert on */ - reg_w(gspca_dev, 0x01, ®01, 1); + reg_w(gspca_dev, 0x01, &sn9c10x[0x01 - 1], 1); /* reg 0x17 SensorClk enable inv Clk 0x60 */ - reg_w(gspca_dev, 0x17, ®17, 1); + reg_w(gspca_dev, 0x17, &sn9c10x[0x17 - 1], 1); /* Set the registers from the template */ reg_w_big(gspca_dev, 0x01, sn9c10x, l); switch (sd->sensor) { -- cgit v1.2.3 From f8f6296adad30cadd65555dfde489d1080b2001c Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Wed, 23 Jul 2008 20:28:23 -0300 Subject: V4L/DVB (8461): cx18: Fix 32 kHz audio sample output rate for analog tuner SIF input cx18: Fix 32 kHz audio sample output rate for analog tuner SIF input so it works. The AUX_PLL VCO was being operated at 196.6 MHz out of the spec'ed 200-600 MHz range. Fixed the multipler and post dividers to operate the VCO within specification and added comments on how magic numbers are derived. Thanks to Hans Verkuil for pointing out this interesting problem to solve. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-av-audio.c | 41 ++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c index c40a286de1b..7245d37ef34 100644 --- a/drivers/media/video/cx18/cx18-av-audio.c +++ b/drivers/media/video/cx18/cx18-av-audio.c @@ -30,7 +30,6 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) if (freq != 32000 && freq != 44100 && freq != 48000) return -EINVAL; - /* common for all inputs and rates */ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ cx18_av_write(cx, 0x127, 0x50); @@ -38,15 +37,20 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) switch (freq) { case 32000: /* VID_PLL and AUX_PLL */ - cx18_av_write4(cx, 0x108, 0x1006040f); + cx18_av_write4(cx, 0x108, 0x1408040f); /* AUX_PLL_FRAC */ - cx18_av_write4(cx, 0x110, 0x01bb39ee); + /* 0x8.9504318a * 28,636,363.636 / 0x14 = 32000 * 384 */ + cx18_av_write4(cx, 0x110, 0x012a0863); - /* src3/4/6_ctl = 0x0801f77f */ + /* src3/4/6_ctl */ + /* 0x1.f77f = (4 * 15734.26) / 32000 */ cx18_av_write4(cx, 0x900, 0x0801f77f); cx18_av_write4(cx, 0x904, 0x0801f77f); cx18_av_write4(cx, 0x90c, 0x0801f77f); + + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */ + cx18_av_write(cx, 0x127, 0x54); break; case 44100: @@ -54,9 +58,11 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) cx18_av_write4(cx, 0x108, 0x1009040f); /* AUX_PLL_FRAC */ + /* 0x9.7635eb * 28,636,363 / 0x10 = 44100 * 384 */ cx18_av_write4(cx, 0x110, 0x00ec6bd6); - /* src3/4/6_ctl = 0x08016d59 */ + /* src3/4/6_ctl */ + /* 0x1.6d59 = (4 * 15734.26) / 44100 */ cx18_av_write4(cx, 0x900, 0x08016d59); cx18_av_write4(cx, 0x904, 0x08016d59); cx18_av_write4(cx, 0x90c, 0x08016d59); @@ -67,9 +73,11 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) cx18_av_write4(cx, 0x108, 0x100a040f); /* AUX_PLL_FRAC */ + /* 0xa.4c6b728 * 28,636,363 / 0x10 = 48000 * 384 */ cx18_av_write4(cx, 0x110, 0x0098d6e5); - /* src3/4/6_ctl = 0x08014faa */ + /* src3/4/6_ctl */ + /* 0x1.4faa = (4 * 15734.26) / 48000 */ cx18_av_write4(cx, 0x900, 0x08014faa); cx18_av_write4(cx, 0x904, 0x08014faa); cx18_av_write4(cx, 0x90c, 0x08014faa); @@ -82,12 +90,15 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) cx18_av_write4(cx, 0x108, 0x1e08040f); /* AUX_PLL_FRAC */ + /* 0x8.9504348 * 28,636,363 / 0x1e = 32000 * 256 */ cx18_av_write4(cx, 0x110, 0x012a0869); - /* src1_ctl = 0x08010000 */ + /* src1_ctl */ + /* 0x1.0000 = 32000/32000 */ cx18_av_write4(cx, 0x8f8, 0x08010000); - /* src3/4/6_ctl = 0x08020000 */ + /* src3/4/6_ctl */ + /* 0x2.0000 = 2 * (32000/32000) */ cx18_av_write4(cx, 0x900, 0x08020000); cx18_av_write4(cx, 0x904, 0x08020000); cx18_av_write4(cx, 0x90c, 0x08020000); @@ -101,12 +112,15 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) cx18_av_write4(cx, 0x108, 0x1809040f); /* AUX_PLL_FRAC */ + /* 0x9.76346B * 28,636,363 / 0x18 = 44100 * 256 */ cx18_av_write4(cx, 0x110, 0x00ec6bd6); - /* src1_ctl = 0x08010000 */ + /* src1_ctl */ + /* 0x1.60cd = 44100/32000 */ cx18_av_write4(cx, 0x8f8, 0x080160cd); - /* src3/4/6_ctl = 0x08020000 */ + /* src3/4/6_ctl */ + /* 0x1.7385 = 2 * (32000/44100) */ cx18_av_write4(cx, 0x900, 0x08017385); cx18_av_write4(cx, 0x904, 0x08017385); cx18_av_write4(cx, 0x90c, 0x08017385); @@ -117,12 +131,15 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) cx18_av_write4(cx, 0x108, 0x180a040f); /* AUX_PLL_FRAC */ + /* 0xa.4c6b728 * 28,636,363 / 0x18 = 48000 * 256 */ cx18_av_write4(cx, 0x110, 0x0098d6e5); - /* src1_ctl = 0x08010000 */ + /* src1_ctl */ + /* 0x1.8000 = 48000/32000 */ cx18_av_write4(cx, 0x8f8, 0x08018000); - /* src3/4/6_ctl = 0x08020000 */ + /* src3/4/6_ctl */ + /* 0x1.5555 = 2 * (32000/48000) */ cx18_av_write4(cx, 0x900, 0x08015555); cx18_av_write4(cx, 0x904, 0x08015555); cx18_av_write4(cx, 0x90c, 0x08015555); -- cgit v1.2.3 From 35f92b2af8230ffc1146e2317e2068fefd7caacb Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Fri, 25 Jul 2008 15:03:08 -0300 Subject: V4L/DVB (8462): cx18: Lock the aux PLL to the video pixle rate for analog captures cx18: Lock the aux PLL to the video pixel rate for analog captures. The datasheet for the CX25840 says this is important for MPEG encoding applications. To ensure the PLL locking was correct, also fixed the aux PLL's multiplier to be computed based on a precise crystal freq of 4.5 MHz/286 * 455/2 * 8 = 28636363.6363... instead of the imporperly rounded 28636363. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-av-audio.c | 80 ++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c index 7245d37ef34..0b55837880a 100644 --- a/drivers/media/video/cx18/cx18-av-audio.c +++ b/drivers/media/video/cx18/cx18-av-audio.c @@ -51,6 +51,16 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */ cx18_av_write(cx, 0x127, 0x54); + + /* AUD_COUNT = 0x2fff = 8 samples * 4 * 384 - 1 */ + cx18_av_write4(cx, 0x12c, 0x11202fff); + + /* + * EN_AV_LOCK = 1 + * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 = + * ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa10d2ef8); break; case 44100: @@ -58,14 +68,24 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) cx18_av_write4(cx, 0x108, 0x1009040f); /* AUX_PLL_FRAC */ - /* 0x9.7635eb * 28,636,363 / 0x10 = 44100 * 384 */ - cx18_av_write4(cx, 0x110, 0x00ec6bd6); + /* 0x9.7635e7 * 28,636,363.63 / 0x10 = 44100 * 384 */ + cx18_av_write4(cx, 0x110, 0x00ec6bce); /* src3/4/6_ctl */ /* 0x1.6d59 = (4 * 15734.26) / 44100 */ cx18_av_write4(cx, 0x900, 0x08016d59); cx18_av_write4(cx, 0x904, 0x08016d59); cx18_av_write4(cx, 0x90c, 0x08016d59); + + /* AUD_COUNT = 0x92ff = 49 samples * 2 * 384 - 1 */ + cx18_av_write4(cx, 0x12c, 0x112092ff); + + /* + * EN_AV_LOCK = 1 + * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 = + * ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa11d4bf8); break; case 48000: @@ -73,14 +93,24 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) cx18_av_write4(cx, 0x108, 0x100a040f); /* AUX_PLL_FRAC */ - /* 0xa.4c6b728 * 28,636,363 / 0x10 = 48000 * 384 */ - cx18_av_write4(cx, 0x110, 0x0098d6e5); + /* 0xa.4c6b6ea * 28,636,363.63 / 0x10 = 48000 * 384 */ + cx18_av_write4(cx, 0x110, 0x0098d6dd); /* src3/4/6_ctl */ /* 0x1.4faa = (4 * 15734.26) / 48000 */ cx18_av_write4(cx, 0x900, 0x08014faa); cx18_av_write4(cx, 0x904, 0x08014faa); cx18_av_write4(cx, 0x90c, 0x08014faa); + + /* AUD_COUNT = 0x5fff = 4 samples * 16 * 384 - 1 */ + cx18_av_write4(cx, 0x12c, 0x11205fff); + + /* + * EN_AV_LOCK = 1 + * VID_COUNT = 0x1193f8 = 143999.000 * 8 = + * ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa11193f8); break; } } else { @@ -90,8 +120,8 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) cx18_av_write4(cx, 0x108, 0x1e08040f); /* AUX_PLL_FRAC */ - /* 0x8.9504348 * 28,636,363 / 0x1e = 32000 * 256 */ - cx18_av_write4(cx, 0x110, 0x012a0869); + /* 0x8.9504318 * 28,636,363.63 / 0x1e = 32000 * 256 */ + cx18_av_write4(cx, 0x110, 0x012a0863); /* src1_ctl */ /* 0x1.0000 = 32000/32000 */ @@ -105,6 +135,16 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */ cx18_av_write(cx, 0x127, 0x54); + + /* AUD_COUNT = 0x1fff = 8 samples * 4 * 256 - 1 */ + cx18_av_write4(cx, 0x12c, 0x11201fff); + + /* + * EN_AV_LOCK = 1 + * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 = + * ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa10d2ef8); break; case 44100: @@ -112,8 +152,8 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) cx18_av_write4(cx, 0x108, 0x1809040f); /* AUX_PLL_FRAC */ - /* 0x9.76346B * 28,636,363 / 0x18 = 44100 * 256 */ - cx18_av_write4(cx, 0x110, 0x00ec6bd6); + /* 0x9.7635e74 * 28,636,363.63 / 0x18 = 44100 * 256 */ + cx18_av_write4(cx, 0x110, 0x00ec6bce); /* src1_ctl */ /* 0x1.60cd = 44100/32000 */ @@ -124,6 +164,16 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) cx18_av_write4(cx, 0x900, 0x08017385); cx18_av_write4(cx, 0x904, 0x08017385); cx18_av_write4(cx, 0x90c, 0x08017385); + + /* AUD_COUNT = 0x61ff = 49 samples * 2 * 256 - 1 */ + cx18_av_write4(cx, 0x12c, 0x112061ff); + + /* + * EN_AV_LOCK = 1 + * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 = + * ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa11d4bf8); break; case 48000: @@ -131,8 +181,8 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) cx18_av_write4(cx, 0x108, 0x180a040f); /* AUX_PLL_FRAC */ - /* 0xa.4c6b728 * 28,636,363 / 0x18 = 48000 * 256 */ - cx18_av_write4(cx, 0x110, 0x0098d6e5); + /* 0xa.4c6b6ea * 28,636,363.63 / 0x18 = 48000 * 256 */ + cx18_av_write4(cx, 0x110, 0x0098d6dd); /* src1_ctl */ /* 0x1.8000 = 48000/32000 */ @@ -143,6 +193,16 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) cx18_av_write4(cx, 0x900, 0x08015555); cx18_av_write4(cx, 0x904, 0x08015555); cx18_av_write4(cx, 0x90c, 0x08015555); + + /* AUD_COUNT = 0x3fff = 4 samples * 16 * 256 - 1 */ + cx18_av_write4(cx, 0x12c, 0x11203fff); + + /* + * EN_AV_LOCK = 1 + * VID_COUNT = 0x1193f8 = 143999.000 * 8 = + * ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa11193f8); break; } } -- cgit v1.2.3 From 28901ab621bb56cd2aa9670dc7ce016ba80ec45c Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 28 Jun 2008 00:48:18 -0300 Subject: V4L/DVB (8464): cx23885: Bugfix for concurrent use of /dev/video0 and /dev/video1 With the HVR1800, trying to use video0 and video1 simultaneously caused buffer corruption in the PCIe bridge. This fix reallocates video1 buffer locations to avoid the issue. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index d17343ea0d3..e14371ef126 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -104,8 +104,8 @@ static struct sram_channel cx23887_sram_channels[] = { [SRAM_CH03] = { .name = "TS1 B", .cmds_start = 0x100A0, - .ctrl_start = 0x10780, - .cdt = 0x10400, + .ctrl_start = 0x10670, + .cdt = 0x10810, .fifo_start = 0x5000, .fifo_size = 0x1000, .ptr1_reg = DMA3_PTR1, -- cgit v1.2.3 From ecda5966c90746a044ff68e78b1062adcddd9664 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 28 Jun 2008 00:52:45 -0300 Subject: V4L/DVB (8465): cx23885: Ensure PAD_CTRL is always reset to a sensible default PAD_CTRL controls TS1 and TS2 input and output states, if the register became corrupt the driver was never able to recover. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index e14371ef126..f5afc8d7cb1 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -460,6 +460,7 @@ static void cx23885_reset(struct cx23885_dev *dev) cx_write(AUDIO_INT_INT_STAT, 0xffffffff); cx_write(AUDIO_EXT_INT_STAT, 0xffffffff); cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000); + cx_write(PAD_CTRL, 0x00500300); mdelay(100); -- cgit v1.2.3 From 52ce27bfc4d302a3e28267a5820a8b031ceccee9 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 28 Jun 2008 00:58:35 -0300 Subject: V4L/DVB (8466): cx23885: Bugfix - DVB Transport cards using DVB port VIDB/TS1 did not stream. Certain DVB cards that have demodulators on TS1/VIDB were not streaming packets. This ensure the pin directions on PAD_CTRL are set correctly, solving the issue. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index f5afc8d7cb1..b96016d1d0f 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1084,7 +1084,21 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_write(port->reg_gpcnt_ctl, 3); q->count = 1; - if (cx23885_boards[dev->board].portb & CX23885_MPEG_ENCODER) { + /* Set VIDB pins to input */ + if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { + reg = cx_read(PAD_CTRL); + reg &= ~0x3; /* Clear TS1_OE & TS1_SOP_OE */ + cx_write(PAD_CTRL, reg); + } + + /* Set VIDC pins to input */ + if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { + reg = cx_read(PAD_CTRL); + reg &= ~0x4; /* Clear TS2_SOP_OE */ + cx_write(PAD_CTRL, reg); + } + + if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { reg = cx_read(PAD_CTRL); reg = reg & ~0x1; /* Clear TS1_OE */ @@ -1134,7 +1148,7 @@ static int cx23885_stop_dma(struct cx23885_tsport *port) cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val); cx_clear(port->reg_dma_ctl, port->dma_ctl_val); - if (cx23885_boards[dev->board].portb & CX23885_MPEG_ENCODER) { + if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { reg = cx_read(PAD_CTRL); -- cgit v1.2.3 From 7b9139086abca60b762d1b01231db88abfb666d5 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 30 Jun 2008 20:54:34 -0300 Subject: V4L/DVB (8467): cx23885: Minor cleanup to the debuging output for a specific register. Don't display the register when it's not appropriate for the specific port. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index b96016d1d0f..83067a49a7b 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1011,8 +1011,9 @@ static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl)); dprintk(1, "%s() dma_ctl(0x%08X) 0x%08x\n", __func__, port->reg_dma_ctl, cx_read(port->reg_dma_ctl)); - dprintk(1, "%s() src_sel(0x%08X) 0x%08x\n", __func__, - port->reg_src_sel, cx_read(port->reg_src_sel)); + if (port->reg_src_sel) + dprintk(1, "%s() src_sel(0x%08X) 0x%08x\n", __func__, + port->reg_src_sel, cx_read(port->reg_src_sel)); dprintk(1, "%s() lngth(0x%08X) 0x%08x\n", __func__, port->reg_lngth, cx_read(port->reg_lngth)); dprintk(1, "%s() hw_sop_ctrl(0x%08X) 0x%08x\n", __func__, -- cgit v1.2.3 From aaadeac88add22c4b2e2e7d17af1c5bae2d3fe17 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 30 Jun 2008 20:58:38 -0300 Subject: V4L/DVB (8468): cx23885: Ensure the second transport port is enabled for streaming. It was previously disabled pending a bugfix, which has since been resolved. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index fd7112c11d3..f325c123295 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -145,6 +145,7 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP] = { .name = "DViCO FusionHDTV7 Dual Express", + .portb = CX23885_MPEG_DVB, .portc = CX23885_MPEG_DVB, }, }; -- cgit v1.2.3 From 1ecc5aed1ea426dbb7e5cd9a0c980c14c879277b Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 30 Jun 2008 21:23:50 -0300 Subject: V4L/DVB (8469): cx23885: FusionHDTV7 Dual Express toggle reset. Ensure the tuners and demods are brought in and out of reset during driver startup. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index f325c123295..691b35279c2 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -436,6 +436,19 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) mdelay(20); cx_set(GP0_IO, 0x00050005); break; + case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: + /* GPIO-0 xc5000 tuner reset i2c bus 0 */ + /* GPIO-1 s5h1409 demod reset i2c bus 0 */ + /* GPIO-2 xc5000 tuner reset i2c bus 1 */ + /* GPIO-3 s5h1409 demod reset i2c bus 0 */ + + /* Put the parts into reset and back */ + cx_set(GP0_IO, 0x000f0000); + mdelay(20); + cx_clear(GP0_IO, 0x0000000f); + mdelay(20); + cx_set(GP0_IO, 0x000f000f); + break; } } -- cgit v1.2.3 From 6df516905b5c53b306d90be33f9c56434e8db053 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 30 Jun 2008 22:17:05 -0300 Subject: V4L/DVB (8470): cx23885: Add DViCO HDTV7 Dual Express tuner callback support. Ensure the correct tuner gets reset on demand. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 40 ++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 691b35279c2..a19de850955 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -326,25 +326,41 @@ int cx23885_tuner_callback(void *priv, int command, int arg) { struct cx23885_i2c *bus = priv; struct cx23885_dev *dev = bus->dev; + u32 bitmask = 0; + + if (command != 0) { + printk(KERN_ERR "%s(): Unknown command 0x%x.\n", + __func__, command); + return -EINVAL; + } switch(dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1500Q: - if(command == 0) { /* Tuner Reset Command from xc5000 */ - /* Drive the tuner into reset and out */ - cx_clear(GP0_IO, 0x00000004); - mdelay(200); - cx_set(GP0_IO, 0x00000004); - return 0; - } - else { - printk(KERN_ERR - "%s(): Unknow command.\n", __func__); - return -EINVAL; + /* Tuner Reset Command from xc5000 */ + if (command == 0) + bitmask = 0x04; + break; + case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: + if (command == 0) { + + /* Two identical tuners on two different i2c buses, + * we need to reset the correct gpio. */ + if (bus->nr == 0) + bitmask = 0x01; + else if (bus->nr == 1) + bitmask = 0x04; } break; } - return 0; /* Should never be here */ + if (bitmask) { + /* Drive the tuner into reset and back out */ + cx_clear(GP0_IO, bitmask); + mdelay(200); + cx_set(GP0_IO, bitmask); + } + + return 0; } void cx23885_gpio_setup(struct cx23885_dev *dev) -- cgit v1.2.3 From d8d12b4367e2e759f65c5f9dcb94d21ec237bbc5 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 1 Jul 2008 10:43:27 -0300 Subject: V4L/DVB (8471): cx23885: Reallocated the sram to avoid concurrent VIDB/C issues. This may be cx23885 chip specific and may not work on the cx23887. Analog and mpeg encoder streaming are still to be tested. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 83067a49a7b..3ae04d6e136 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -80,8 +80,8 @@ static struct sram_channel cx23887_sram_channels[] = { [SRAM_CH01] = { .name = "VID A", .cmds_start = 0x10000, - .ctrl_start = 0x105b0, - .cdt = 0x107b0, + .ctrl_start = 0x10380, + .cdt = 0x104c0, .fifo_start = 0x40, .fifo_size = 0x2800, .ptr1_reg = DMA1_PTR1, @@ -104,8 +104,8 @@ static struct sram_channel cx23887_sram_channels[] = { [SRAM_CH03] = { .name = "TS1 B", .cmds_start = 0x100A0, - .ctrl_start = 0x10670, - .cdt = 0x10810, + .ctrl_start = 0x10400, + .cdt = 0x10580, .fifo_start = 0x5000, .fifo_size = 0x1000, .ptr1_reg = DMA3_PTR1, @@ -140,8 +140,8 @@ static struct sram_channel cx23887_sram_channels[] = { [SRAM_CH06] = { .name = "TS2 C", .cmds_start = 0x10140, - .ctrl_start = 0x10680, - .cdt = 0x108d0, + .ctrl_start = 0x10440, + .cdt = 0x105e0, .fifo_start = 0x6000, .fifo_size = 0x1000, .ptr1_reg = DMA5_PTR1, @@ -1044,6 +1044,9 @@ static int cx23885_start_dma(struct cx23885_tsport *port, dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__, buf->vb.width, buf->vb.height, buf->vb.field); + /* Stop the fifo and risc engine for this port */ + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); + /* setup fifo + format */ cx23885_sram_channel_setup(dev, &dev->sram_channels[ port->sram_chno ], -- cgit v1.2.3 From 7e994302ed3fc6d209ce247ad5b6d9c2499bf7c2 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 1 Jul 2008 21:18:00 -0300 Subject: V4L/DVB (8472): cx23885: SRAM changes for the 885 and 887 silicon parts. In a previous patch I merged both memory maps into a single struct, believing that they could be combined. We've since found problems with streaming multiple channels on the 885. I'm restoring the multiple memory map structs - in line with the windows driver. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 116 ++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 3ae04d6e136..6286a9cf957 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -76,7 +76,7 @@ LIST_HEAD(cx23885_devlist); * 0x00010ea0 0x00010xxx Free */ -static struct sram_channel cx23887_sram_channels[] = { +static struct sram_channel cx23885_sram_channels[] = { [SRAM_CH01] = { .name = "VID A", .cmds_start = 0x10000, @@ -187,6 +187,117 @@ static struct sram_channel cx23887_sram_channels[] = { }, }; +static struct sram_channel cx23887_sram_channels[] = { + [SRAM_CH01] = { + .name = "VID A", + .cmds_start = 0x10000, + .ctrl_start = 0x105b0, + .cdt = 0x107b0, + .fifo_start = 0x40, + .fifo_size = 0x2800, + .ptr1_reg = DMA1_PTR1, + .ptr2_reg = DMA1_PTR2, + .cnt1_reg = DMA1_CNT1, + .cnt2_reg = DMA1_CNT2, + }, + [SRAM_CH02] = { + .name = "ch2", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA2_PTR1, + .ptr2_reg = DMA2_PTR2, + .cnt1_reg = DMA2_CNT1, + .cnt2_reg = DMA2_CNT2, + }, + [SRAM_CH03] = { + .name = "TS1 B", + .cmds_start = 0x100A0, + .ctrl_start = 0x10630, + .cdt = 0x10870, + .fifo_start = 0x5000, + .fifo_size = 0x1000, + .ptr1_reg = DMA3_PTR1, + .ptr2_reg = DMA3_PTR2, + .cnt1_reg = DMA3_CNT1, + .cnt2_reg = DMA3_CNT2, + }, + [SRAM_CH04] = { + .name = "ch4", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA4_PTR1, + .ptr2_reg = DMA4_PTR2, + .cnt1_reg = DMA4_CNT1, + .cnt2_reg = DMA4_CNT2, + }, + [SRAM_CH05] = { + .name = "ch5", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH06] = { + .name = "TS2 C", + .cmds_start = 0x10140, + .ctrl_start = 0x10670, + .cdt = 0x108d0, + .fifo_start = 0x6000, + .fifo_size = 0x1000, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH07] = { + .name = "ch7", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA6_PTR1, + .ptr2_reg = DMA6_PTR2, + .cnt1_reg = DMA6_CNT1, + .cnt2_reg = DMA6_CNT2, + }, + [SRAM_CH08] = { + .name = "ch8", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA7_PTR1, + .ptr2_reg = DMA7_PTR2, + .cnt1_reg = DMA7_CNT1, + .cnt2_reg = DMA7_CNT2, + }, + [SRAM_CH09] = { + .name = "ch9", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA8_PTR1, + .ptr2_reg = DMA8_PTR2, + .cnt1_reg = DMA8_CNT1, + .cnt2_reg = DMA8_CNT2, + }, +}; + static int cx23885_risc_decode(u32 risc) { static char *instr[16] = { @@ -626,7 +737,6 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) atomic_inc(&dev->refcount); dev->nr = cx23885_devcount++; - dev->sram_channels = cx23887_sram_channels; sprintf(dev->name, "cx23885[%d]", dev->nr); mutex_lock(&devlist); @@ -638,11 +748,13 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->bridge = CX23885_BRIDGE_887; /* Apply a sensible clock frequency for the PCIe bridge */ dev->clk_freq = 25000000; + dev->sram_channels = cx23887_sram_channels; } else if(dev->pci->device == 0x8852) { dev->bridge = CX23885_BRIDGE_885; /* Apply a sensible clock frequency for the PCIe bridge */ dev->clk_freq = 28000000; + dev->sram_channels = cx23885_sram_channels; } else BUG(); -- cgit v1.2.3 From 31335b13ca3925f361702ca4fc895ab165beddb9 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Fri, 25 Jul 2008 19:35:31 -0300 Subject: V4L/DVB (8474): pvrusb2: Enable IR chip on HVR-1900 class devices The Zilog IR chip on HVR-1900 devices is held in reset when the device initializes. We have to bring this chip out of reset before LIRC has any chance of operating the chip. So do it. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-devattr.c | 5 ++++- drivers/media/video/pvrusb2/pvrusb2-devattr.h | 26 +++++++++++++++++--------- drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h | 2 ++ drivers/media/video/pvrusb2/pvrusb2-hdw.c | 9 +++++++++ drivers/media/video/pvrusb2/pvrusb2-i2c-core.c | 4 +++- 5 files changed, 35 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 5d036e7e3f0..e3b05119708 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -97,13 +97,13 @@ static const struct pvr2_device_desc pvr2_device_24xxx = { .flag_has_cx25840 = !0, .flag_has_wm8775 = !0, .flag_has_hauppauge_rom = !0, - .flag_has_hauppauge_custom_ir = !0, .flag_has_analogtuner = !0, .flag_has_fmradio = !0, .flag_has_composite = !0, .flag_has_svideo = !0, .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, + .ir_scheme = PVR2_IR_SCHEME_24XXX, }; @@ -344,6 +344,7 @@ static const struct pvr2_device_desc pvr2_device_73xxx = { .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE, .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, + .ir_scheme = PVR2_IR_SCHEME_ZILOG, #ifdef CONFIG_VIDEO_PVRUSB2_DVB .dvb_props = &pvr2_73xxx_dvb_props, #endif @@ -453,6 +454,7 @@ static const struct pvr2_device_desc pvr2_device_750xx = { .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE, .default_std_mask = V4L2_STD_NTSC_M, .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, + .ir_scheme = PVR2_IR_SCHEME_ZILOG, #ifdef CONFIG_VIDEO_PVRUSB2_DVB .dvb_props = &pvr2_750xx_dvb_props, #endif @@ -474,6 +476,7 @@ static const struct pvr2_device_desc pvr2_device_751xx = { .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE, .default_std_mask = V4L2_STD_NTSC_M, .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, + .ir_scheme = PVR2_IR_SCHEME_ZILOG, #ifdef CONFIG_VIDEO_PVRUSB2_DVB .dvb_props = &pvr2_751xx_dvb_props, #endif diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h index e23ce1d2edd..cb3a33eb027 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h @@ -48,6 +48,10 @@ struct pvr2_string_table { #define PVR2_LED_SCHEME_NONE 0 #define PVR2_LED_SCHEME_HAUPPAUGE 1 +#define PVR2_IR_SCHEME_NONE 0 +#define PVR2_IR_SCHEME_24XXX 1 +#define PVR2_IR_SCHEME_ZILOG 2 + /* This describes a particular hardware type (except for the USB device ID which must live in a separate structure due to environmental constraints). See the top of pvrusb2-hdw.c for where this is @@ -126,15 +130,19 @@ struct pvr2_device_desc { ensure that it is found. */ unsigned int flag_has_wm8775:1; - /* Device has IR hardware that can be faked into looking like a - normal Hauppauge i2c IR receiver. This is currently very - specific to the 24xxx device, where Hauppauge had replaced their - 'standard' I2C IR receiver with a bunch of FPGA logic controlled - directly via the FX2. Turning this on tells the pvrusb2 driver - to virtualize the presence of the non-existant IR receiver chip and - implement the virtual receiver in terms of appropriate FX2 - commands. */ - unsigned int flag_has_hauppauge_custom_ir:1; + /* Indicate any specialized IR scheme that might need to be + supported by this driver. If not set, then it is assumed that + IR can work without help from the driver (which is frequently + the case). This is otherwise set to one of + PVR2_IR_SCHEME_xxxx. For "xxxx", the value "24XXX" indicates a + Hauppauge 24xxx class device which has an FPGA-hosted IR + receiver that can only be reached via FX2 command codes. In + that case the pvrusb2 driver will emulate the behavior of the + older 29xxx device's IR receiver (a "virtual" I2C chip) in terms + of those command codes. For the value "ZILOG", we're dealing + with an IR chip that must be taken out of reset via another FX2 + command code (which is the case for HVR-1950 devices). */ + unsigned int ir_scheme:2; /* These bits define which kinds of sources the device can handle. Note: Digital tuner presence is inferred by the diff --git a/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h index b58369e7f30..614755ea2ea 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h +++ b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h @@ -24,6 +24,8 @@ #define FX2CMD_MEM_WRITE_DWORD 0x01u #define FX2CMD_MEM_READ_DWORD 0x02u +#define FX2CMD_HCW_ZILOG_RESET 0x10u /* 1=reset 0=release */ + #define FX2CMD_MEM_READ_64BYTES 0x28u #define FX2CMD_REG_WRITE 0x04u diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index a5217a2cf4c..f051c6aa7f1 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -250,6 +250,7 @@ struct pvr2_fx2cmd_descdef { static const struct pvr2_fx2cmd_descdef pvr2_fx2cmd_desc[] = { {FX2CMD_MEM_WRITE_DWORD, "write encoder dword"}, {FX2CMD_MEM_READ_DWORD, "read encoder dword"}, + {FX2CMD_HCW_ZILOG_RESET, "zilog IR reset control"}, {FX2CMD_MEM_READ_64BYTES, "read encoder 64bytes"}, {FX2CMD_REG_WRITE, "write encoder register"}, {FX2CMD_REG_READ, "read encoder register"}, @@ -1711,6 +1712,14 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) if (!pvr2_hdw_dev_ok(hdw)) return; } + /* Take the IR chip out of reset, if appropriate */ + if (hdw->hdw_desc->ir_scheme == PVR2_IR_SCHEME_ZILOG) { + pvr2_issue_simple_cmd(hdw, + FX2CMD_HCW_ZILOG_RESET | + (1 << 8) | + ((0) << 16)); + } + // This step MUST happen after the earlier powerup step. pvr2_i2c_core_init(hdw); if (!pvr2_hdw_dev_ok(hdw)) return; diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 9d3c18b2474..e600576a6c4 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -979,7 +979,9 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw) printk(KERN_INFO "%s: IR disabled\n",hdw->name); hdw->i2c_func[0x18] = i2c_black_hole; } else if (ir_mode[hdw->unit_number] == 1) { - if (hdw->hdw_desc->flag_has_hauppauge_custom_ir) { + if (hdw->hdw_desc->ir_scheme == PVR2_IR_SCHEME_24XXX) { + /* This comment is present PURELY to get + checkpatch.pl to STFU. Lovely, eh? */ hdw->i2c_func[0x18] = i2c_24xxx_ir; } } -- cgit v1.2.3 From d417f711b9180c4851cfdc19db030878918eac88 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Fri, 25 Jul 2008 19:50:52 -0300 Subject: V4L/DVB (8475): pvrusb2: Cosmetic macro fix (benign) Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-context.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/video/pvrusb2/pvrusb2-context.h index 61801291c2a..d657e53bbfa 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.h +++ b/drivers/media/video/pvrusb2/pvrusb2-context.h @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ -#ifndef __PVRUSB2_BASE_H -#define __PVRUSB2_BASE_H +#ifndef __PVRUSB2_CONTEXT_H +#define __PVRUSB2_CONTEXT_H #include #include -- cgit v1.2.3 From 38f9d308597fe3f8d52bfa30e7ed6c742b85a1db Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Jul 2008 05:09:15 -0300 Subject: V4L/DVB (8477): v4l: remove obsolete audiochip.h Converted the last users of audiochip.h to the v4l2-chip-ident.h header and remove the now unused audiochip.h header. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 2 +- drivers/media/video/cx88/cx88-video.c | 4 +- drivers/media/video/cx88/cx88.h | 4 +- drivers/media/video/em28xx/em28xx-cards.c | 4 +- drivers/media/video/tveeprom.c | 104 ++++++++++++------------ drivers/media/video/usbvision/usbvision-core.c | 1 - drivers/media/video/usbvision/usbvision-video.c | 1 - 7 files changed, 60 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index fa6d398e97b..de199a206a1 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1348,7 +1348,7 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .audio_chip = AUDIO_CHIP_WM8775, + .audio_chip = V4L2_IDENT_WM8775, .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index d08c11eb8a7..f8cc55db9f4 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -448,7 +448,7 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) the initialization. Some boards may use different routes for different inputs. HVR-1300 surely does */ if (core->board.audio_chip && - core->board.audio_chip == AUDIO_CHIP_WM8775) { + core->board.audio_chip == V4L2_IDENT_WM8775) { struct v4l2_routing route; route.input = INPUT(input).audioroute; @@ -1867,7 +1867,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, /* load and configure helper modules */ - if (core->board.audio_chip == AUDIO_CHIP_WM8775) + if (core->board.audio_chip == V4L2_IDENT_WM8775) request_module("wm8775"); switch (core->boardnr) { diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 14ac173f407..54fe6509471 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -29,8 +29,8 @@ #include #include #include +#include #include -#include #if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) #include #endif @@ -252,7 +252,7 @@ struct cx88_board { struct cx88_input input[MAX_CX88_INPUT]; struct cx88_input radio; enum cx88_board_type mpeg; - enum audiochip audio_chip; + unsigned int audio_chip; }; struct cx88_subid { diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 05f0d5a1505..6e0eb950ab8 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -32,8 +32,8 @@ #include #include #include -#include #include +#include #include "em28xx.h" @@ -836,7 +836,7 @@ void em28xx_card_setup(struct em28xx *dev) dev->tuner_type = tv.tuner_type; - if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { + if (tv.audio_processor == V4L2_IDENT_MSPX4XX) { dev->i2s_speed = 2048000; dev->has_msp34xx = 1; } diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 9da0e1807ff..93954c14323 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver"); MODULE_AUTHOR("John Klar"); @@ -261,70 +261,72 @@ hauppauge_tuner[] = { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, { TUNER_PHILIPS_TDA8290, "Philips 18271_8295"}, /* 150-159 */ - { TUNER_ABSENT, "Xceive XC5000"}, + { TUNER_ABSENT, "Xceive XC5000"}, }; +/* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are + * internal to a video chip, i.e. not a separate audio chip. */ static struct HAUPPAUGE_AUDIOIC { - enum audiochip id; + u32 id; char *name; } audioIC[] = { /* 0-4 */ - {AUDIO_CHIP_NONE, "None"}, - {AUDIO_CHIP_TEA6300, "TEA6300"}, - {AUDIO_CHIP_TEA6300, "TEA6320"}, - {AUDIO_CHIP_TDA985X, "TDA9850"}, - {AUDIO_CHIP_MSP34XX, "MSP3400C"}, + { V4L2_IDENT_NONE, "None" }, + { V4L2_IDENT_UNKNOWN, "TEA6300" }, + { V4L2_IDENT_UNKNOWN, "TEA6320" }, + { V4L2_IDENT_UNKNOWN, "TDA9850" }, + { V4L2_IDENT_MSPX4XX, "MSP3400C" }, /* 5-9 */ - {AUDIO_CHIP_MSP34XX, "MSP3410D"}, - {AUDIO_CHIP_MSP34XX, "MSP3415"}, - {AUDIO_CHIP_MSP34XX, "MSP3430"}, - {AUDIO_CHIP_MSP34XX, "MSP3438"}, - {AUDIO_CHIP_UNKNOWN, "CS5331"}, + { V4L2_IDENT_MSPX4XX, "MSP3410D" }, + { V4L2_IDENT_MSPX4XX, "MSP3415" }, + { V4L2_IDENT_MSPX4XX, "MSP3430" }, + { V4L2_IDENT_MSPX4XX, "MSP3438" }, + { V4L2_IDENT_UNKNOWN, "CS5331" }, /* 10-14 */ - {AUDIO_CHIP_MSP34XX, "MSP3435"}, - {AUDIO_CHIP_MSP34XX, "MSP3440"}, - {AUDIO_CHIP_MSP34XX, "MSP3445"}, - {AUDIO_CHIP_MSP34XX, "MSP3411"}, - {AUDIO_CHIP_MSP34XX, "MSP3416"}, + { V4L2_IDENT_MSPX4XX, "MSP3435" }, + { V4L2_IDENT_MSPX4XX, "MSP3440" }, + { V4L2_IDENT_MSPX4XX, "MSP3445" }, + { V4L2_IDENT_MSPX4XX, "MSP3411" }, + { V4L2_IDENT_MSPX4XX, "MSP3416" }, /* 15-19 */ - {AUDIO_CHIP_MSP34XX, "MSP3425"}, - {AUDIO_CHIP_MSP34XX, "MSP3451"}, - {AUDIO_CHIP_MSP34XX, "MSP3418"}, - {AUDIO_CHIP_UNKNOWN, "Type 0x12"}, - {AUDIO_CHIP_UNKNOWN, "OKI7716"}, + { V4L2_IDENT_MSPX4XX, "MSP3425" }, + { V4L2_IDENT_MSPX4XX, "MSP3451" }, + { V4L2_IDENT_MSPX4XX, "MSP3418" }, + { V4L2_IDENT_UNKNOWN, "Type 0x12" }, + { V4L2_IDENT_UNKNOWN, "OKI7716" }, /* 20-24 */ - {AUDIO_CHIP_MSP34XX, "MSP4410"}, - {AUDIO_CHIP_MSP34XX, "MSP4420"}, - {AUDIO_CHIP_MSP34XX, "MSP4440"}, - {AUDIO_CHIP_MSP34XX, "MSP4450"}, - {AUDIO_CHIP_MSP34XX, "MSP4408"}, + { V4L2_IDENT_MSPX4XX, "MSP4410" }, + { V4L2_IDENT_MSPX4XX, "MSP4420" }, + { V4L2_IDENT_MSPX4XX, "MSP4440" }, + { V4L2_IDENT_MSPX4XX, "MSP4450" }, + { V4L2_IDENT_MSPX4XX, "MSP4408" }, /* 25-29 */ - {AUDIO_CHIP_MSP34XX, "MSP4418"}, - {AUDIO_CHIP_MSP34XX, "MSP4428"}, - {AUDIO_CHIP_MSP34XX, "MSP4448"}, - {AUDIO_CHIP_MSP34XX, "MSP4458"}, - {AUDIO_CHIP_MSP34XX, "Type 0x1d"}, + { V4L2_IDENT_MSPX4XX, "MSP4418" }, + { V4L2_IDENT_MSPX4XX, "MSP4428" }, + { V4L2_IDENT_MSPX4XX, "MSP4448" }, + { V4L2_IDENT_MSPX4XX, "MSP4458" }, + { V4L2_IDENT_MSPX4XX, "Type 0x1d" }, /* 30-34 */ - {AUDIO_CHIP_INTERNAL, "CX880"}, - {AUDIO_CHIP_INTERNAL, "CX881"}, - {AUDIO_CHIP_INTERNAL, "CX883"}, - {AUDIO_CHIP_INTERNAL, "CX882"}, - {AUDIO_CHIP_INTERNAL, "CX25840"}, + { V4L2_IDENT_AMBIGUOUS, "CX880" }, + { V4L2_IDENT_AMBIGUOUS, "CX881" }, + { V4L2_IDENT_AMBIGUOUS, "CX883" }, + { V4L2_IDENT_AMBIGUOUS, "CX882" }, + { V4L2_IDENT_AMBIGUOUS, "CX25840" }, /* 35-39 */ - {AUDIO_CHIP_INTERNAL, "CX25841"}, - {AUDIO_CHIP_INTERNAL, "CX25842"}, - {AUDIO_CHIP_INTERNAL, "CX25843"}, - {AUDIO_CHIP_INTERNAL, "CX23418"}, - {AUDIO_CHIP_INTERNAL, "CX23885"}, + { V4L2_IDENT_AMBIGUOUS, "CX25841" }, + { V4L2_IDENT_AMBIGUOUS, "CX25842" }, + { V4L2_IDENT_AMBIGUOUS, "CX25843" }, + { V4L2_IDENT_AMBIGUOUS, "CX23418" }, + { V4L2_IDENT_AMBIGUOUS, "CX23885" }, /* 40-44 */ - {AUDIO_CHIP_INTERNAL, "CX23888"}, - {AUDIO_CHIP_INTERNAL, "SAA7131"}, - {AUDIO_CHIP_INTERNAL, "CX23887"}, - {AUDIO_CHIP_INTERNAL, "SAA7164"}, - {AUDIO_CHIP_INTERNAL, "AU8522"}, + { V4L2_IDENT_AMBIGUOUS, "CX23888" }, + { V4L2_IDENT_AMBIGUOUS, "SAA7131" }, + { V4L2_IDENT_AMBIGUOUS, "CX23887" }, + { V4L2_IDENT_AMBIGUOUS, "SAA7164" }, + { V4L2_IDENT_AMBIGUOUS, "AU8522" }, }; /* This list is supplied by Hauppauge. Thanks! */ @@ -509,7 +511,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, if (audioic < ARRAY_SIZE(audioIC)) tvee->audio_processor = audioIC[audioic].id; else - tvee->audio_processor = AUDIO_CHIP_UNKNOWN; + tvee->audio_processor = V4L2_IDENT_UNKNOWN; break; /* case 0x03: tag 'EEInfo' */ @@ -542,7 +544,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, if (audioic < ARRAY_SIZE(audioIC)) tvee->audio_processor = audioIC[audioic].id; else - tvee->audio_processor = AUDIO_CHIP_UNKNOWN; + tvee->audio_processor = V4L2_IDENT_UNKNOWN; break; @@ -690,7 +692,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, t_fmt_name2[6], t_fmt_name2[7], t_format2); if (audioic < 0) { tveeprom_info("audio processor is unknown (no idx)\n"); - tvee->audio_processor = AUDIO_CHIP_UNKNOWN; + tvee->audio_processor = V4L2_IDENT_UNKNOWN; } else { if (audioic < ARRAY_SIZE(audioIC)) tveeprom_info("audio processor is %s (idx %d)\n", diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index abf685464b7..7d53de531c4 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -43,7 +43,6 @@ #include #include #include -#include #include diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 56cd685d35e..5984c756203 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -67,7 +67,6 @@ #include #include #include -#include #include -- cgit v1.2.3 From b654fcdc0ea3b6e5724c9873ae062bdfe7f28efe Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 22 Jul 2008 15:50:31 -0300 Subject: V4L/DVB (8479): tveeprom/ivtv: fix usage of has_ir field has_ir was set to and compared to -1 in several cases, even though it is an u32. ivtv also contained a FIXME for an old kernel that could be removed. Thanks to Roel Kluin for creating an initial patch for this. Although I chose a different solution here it did help in pointing out the problem. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 5 ++--- drivers/media/video/tveeprom.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 41fd79279bb..aea1664948c 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -465,9 +465,8 @@ static void ivtv_process_eeprom(struct ivtv *itv) if (itv->options.radio == -1) itv->options.radio = (tv.has_radio != 0); /* only enable newi2c if an IR blaster is present */ - /* FIXME: for 2.6.20 the test against 2 should be removed */ - if (itv->options.newi2c == -1 && tv.has_ir != -1 && tv.has_ir != 2) { - itv->options.newi2c = (tv.has_ir & 2) ? 1 : 0; + if (itv->options.newi2c == -1 && tv.has_ir) { + itv->options.newi2c = (tv.has_ir & 4) ? 1 : 0; if (itv->options.newi2c) { IVTV_INFO("Reopen i2c bus for IR-blaster support\n"); exit_ivtv_i2c(itv); diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 93954c14323..fbfac1b3bd0 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -485,7 +485,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, tvee->has_radio = eeprom_data[i+len-1]; /* old style tag, don't know how to detect IR presence, mark as unknown. */ - tvee->has_ir = -1; + tvee->has_ir = 0; tvee->model = eeprom_data[i+8] + (eeprom_data[i+9] << 8); @@ -605,7 +605,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, case 0x0f: /* tag 'IRInfo' */ - tvee->has_ir = eeprom_data[i+1]; + tvee->has_ir = 1 | (eeprom_data[i+1] << 1); break; /* case 0x10: tag 'VBIInfo' */ @@ -705,14 +705,14 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, tveeprom_info("decoder processor is %s (idx %d)\n", STRM(decoderIC, tvee->decoder_processor), tvee->decoder_processor); - if (tvee->has_ir == -1) - tveeprom_info("has %sradio\n", - tvee->has_radio ? "" : "no "); - else + if (tvee->has_ir) tveeprom_info("has %sradio, has %sIR receiver, has %sIR transmitter\n", tvee->has_radio ? "" : "no ", - (tvee->has_ir & 1) ? "" : "no ", - (tvee->has_ir & 2) ? "" : "no "); + (tvee->has_ir & 2) ? "" : "no ", + (tvee->has_ir & 4) ? "" : "no "); + else + tveeprom_info("has %sradio\n", + tvee->has_radio ? "" : "no "); } EXPORT_SYMBOL(tveeprom_hauppauge_analog); -- cgit v1.2.3 From a399810ca69d9d4bd30ab8c1678c7439e567f90b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 Jul 2008 02:57:38 -0300 Subject: V4L/DVB (8482): videodev: move all ioctl callbacks to a new v4l2_ioctl_ops struct All ioctl callbacks are now stored in a new v4l2_ioctl_ops struct. Drivers fill in a const struct v4l2_ioctl_ops and video_device just contains a const pointer to it. This ensures a clean separation between the const ops struct and the non-const video_device struct. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/dsbr100.c | 19 +- drivers/media/radio/radio-aimslab.c | 15 +- drivers/media/radio/radio-aztech.c | 15 +- drivers/media/radio/radio-cadet.c | 15 +- drivers/media/radio/radio-gemtek-pci.c | 14 +- drivers/media/radio/radio-gemtek.c | 14 +- drivers/media/radio/radio-maestro.c | 12 +- drivers/media/radio/radio-maxiradio.c | 16 +- drivers/media/radio/radio-rtrack2.c | 15 +- drivers/media/radio/radio-sf16fmi.c | 15 +- drivers/media/radio/radio-sf16fmr2.c | 15 +- drivers/media/radio/radio-si470x.c | 21 +- drivers/media/radio/radio-terratec.c | 15 +- drivers/media/radio/radio-trust.c | 15 +- drivers/media/radio/radio-typhoon.c | 15 +- drivers/media/radio/radio-zoltrix.c | 15 +- drivers/media/video/bt8xx/bttv-driver.c | 26 +- drivers/media/video/cafe_ccic.c | 25 +- drivers/media/video/cx18/cx18-ioctl.c | 92 +++--- drivers/media/video/cx23885/cx23885-417.c | 20 +- drivers/media/video/cx23885/cx23885-video.c | 16 +- drivers/media/video/cx88/cx88-blackbird.c | 16 +- drivers/media/video/cx88/cx88-video.c | 33 +- drivers/media/video/em28xx/em28xx-video.c | 46 +-- drivers/media/video/gspca/gspca.c | 16 +- drivers/media/video/ivtv/ivtv-ioctl.c | 130 ++++---- drivers/media/video/meye.c | 18 +- drivers/media/video/s2255drv.c | 16 +- drivers/media/video/saa7134/saa7134-empress.c | 22 +- drivers/media/video/saa7134/saa7134-video.c | 61 ++-- drivers/media/video/soc_camera.c | 56 ++-- drivers/media/video/stk-webcam.c | 31 +- drivers/media/video/usbvision/usbvision-video.c | 38 ++- drivers/media/video/v4l2-ioctl.c | 418 ++++++++++++------------ drivers/media/video/vivi.c | 18 +- drivers/media/video/zr364xx.c | 19 +- 36 files changed, 754 insertions(+), 609 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index 97c6853ad1d..08bf5e8031d 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -445,14 +445,7 @@ static const struct file_operations usb_dsbr100_fops = { .llseek = no_llseek, }; -/* V4L2 interface */ -static struct video_device dsbr100_videodev_template = -{ - .owner = THIS_MODULE, - .name = "D-Link DSB-R 100", - .type = VID_TYPE_TUNER, - .fops = &usb_dsbr100_fops, - .release = video_device_release, +static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -467,6 +460,16 @@ static struct video_device dsbr100_videodev_template = .vidioc_s_input = vidioc_s_input, }; +/* V4L2 interface */ +static struct video_device dsbr100_videodev_template = { + .owner = THIS_MODULE, + .name = "D-Link DSB-R 100", + .type = VID_TYPE_TUNER, + .fops = &usb_dsbr100_fops, + .ioctl_ops = &usb_dsbr100_ioctl_ops, + .release = video_device_release, +}; + /* check if the device is present and register with v4l and usb if it is */ static int usb_dsbr100_probe(struct usb_interface *intf, diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index ec8d64704dd..be9bd7adaf6 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -389,12 +389,7 @@ static const struct file_operations rtrack_fops = { .llseek = no_llseek, }; -static struct video_device rtrack_radio= -{ - .owner = THIS_MODULE, - .name = "RadioTrack radio", - .type = VID_TYPE_TUNER, - .fops = &rtrack_fops, +static const struct v4l2_ioctl_ops rtrack_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -409,6 +404,14 @@ static struct video_device rtrack_radio= .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device rtrack_radio = { + .owner = THIS_MODULE, + .name = "RadioTrack radio", + .type = VID_TYPE_TUNER, + .fops = &rtrack_fops, + .ioctl_ops = &rtrack_ioctl_ops, +}; + static int __init rtrack_init(void) { if(io==-1) diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c index 639164a974a..04c738b62d0 100644 --- a/drivers/media/radio/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c @@ -353,12 +353,7 @@ static const struct file_operations aztech_fops = { .llseek = no_llseek, }; -static struct video_device aztech_radio= -{ - .owner = THIS_MODULE, - .name = "Aztech radio", - .type = VID_TYPE_TUNER, - .fops = &aztech_fops, +static const struct v4l2_ioctl_ops aztech_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -373,6 +368,14 @@ static struct video_device aztech_radio= .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device aztech_radio = { + .owner = THIS_MODULE, + .name = "Aztech radio", + .type = VID_TYPE_TUNER, + .fops = &aztech_fops, + .ioctl_ops = &aztech_ioctl_ops, +}; + module_param_named(debug,aztech_radio.debug, int, 0644); MODULE_PARM_DESC(debug,"activates debug info"); diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 484ea87d7fb..36b850fc14b 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -570,12 +570,7 @@ static const struct file_operations cadet_fops = { .llseek = no_llseek, }; -static struct video_device cadet_radio= -{ - .owner = THIS_MODULE, - .name = "Cadet radio", - .type = VID_TYPE_TUNER, - .fops = &cadet_fops, +static const struct v4l2_ioctl_ops cadet_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -590,6 +585,14 @@ static struct video_device cadet_radio= .vidioc_s_input = vidioc_s_input, }; +static struct video_device cadet_radio = { + .owner = THIS_MODULE, + .name = "Cadet radio", + .type = VID_TYPE_TUNER, + .fops = &cadet_fops, + .ioctl_ops = &cadet_ioctl_ops, +}; + #ifdef CONFIG_PNP static struct pnp_device_id cadet_pnp_devices[] = { diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c index 2b834b95f3e..c41b35f3b12 100644 --- a/drivers/media/radio/radio-gemtek-pci.c +++ b/drivers/media/radio/radio-gemtek-pci.c @@ -375,11 +375,7 @@ static const struct file_operations gemtek_pci_fops = { .llseek = no_llseek, }; -static struct video_device vdev_template = { - .owner = THIS_MODULE, - .name = "Gemtek PCI Radio", - .type = VID_TYPE_TUNER, - .fops = &gemtek_pci_fops, +static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -394,6 +390,14 @@ static struct video_device vdev_template = { .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device vdev_template = { + .owner = THIS_MODULE, + .name = "Gemtek PCI Radio", + .type = VID_TYPE_TUNER, + .fops = &gemtek_pci_fops, + .ioctl_ops = &gemtek_pci_ioctl_ops, +}; + static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id ) { struct gemtek_pci_card *card; diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 4740bacc2f8..f82b59f35e3 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -553,11 +553,7 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) return 0; } -static struct video_device gemtek_radio = { - .owner = THIS_MODULE, - .name = "GemTek Radio card", - .type = VID_TYPE_TUNER, - .fops = &gemtek_fops, +static const struct v4l2_ioctl_ops gemtek_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -572,6 +568,14 @@ static struct video_device gemtek_radio = { .vidioc_s_ctrl = vidioc_s_ctrl }; +static struct video_device gemtek_radio = { + .owner = THIS_MODULE, + .name = "GemTek Radio card", + .type = VID_TYPE_TUNER, + .fops = &gemtek_fops, + .ioctl_ops = &gemtek_ioctl_ops, +}; + /* * Initialization / cleanup related stuff. */ diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index 040a73fac69..d074a8c9067 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c @@ -355,10 +355,7 @@ static u16 __devinit radio_power_on(struct radio_device *dev) return (ofreq == radio_bits_get(dev)); } -static struct video_device maestro_radio = { - .name = "Maestro radio", - .type = VID_TYPE_TUNER, - .fops = &maestro_fops, +static const struct v4l2_ioctl_ops maestro_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -373,6 +370,13 @@ static struct video_device maestro_radio = { .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device maestro_radio = { + .name = "Maestro radio", + .type = VID_TYPE_TUNER, + .fops = &maestro_fops, + .ioctl_ops = &maestro_ioctl_ops, +}; + static int __devinit maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index 9e824a7d5cc..780516daebb 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -374,13 +374,7 @@ static int vidioc_s_ctrl (struct file *file, void *priv, return -EINVAL; } -static struct video_device maxiradio_radio = -{ - .owner = THIS_MODULE, - .name = "Maxi Radio FM2000 radio", - .type = VID_TYPE_TUNER, - .fops = &maxiradio_fops, - +static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -395,6 +389,14 @@ static struct video_device maxiradio_radio = .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device maxiradio_radio = { + .owner = THIS_MODULE, + .name = "Maxi Radio FM2000 radio", + .type = VID_TYPE_TUNER, + .fops = &maxiradio_fops, + .ioctl_ops = &maxiradio_ioctl_ops, +}; + static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { if(!request_region(pci_resource_start(pdev, 0), diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index c3fb270f211..045ae9d1067 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c @@ -295,12 +295,7 @@ static const struct file_operations rtrack2_fops = { .llseek = no_llseek, }; -static struct video_device rtrack2_radio= -{ - .owner = THIS_MODULE, - .name = "RadioTrack II radio", - .type = VID_TYPE_TUNER, - .fops = &rtrack2_fops, +static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -315,6 +310,14 @@ static struct video_device rtrack2_radio= .vidioc_s_input = vidioc_s_input, }; +static struct video_device rtrack2_radio = { + .owner = THIS_MODULE, + .name = "RadioTrack II radio", + .type = VID_TYPE_TUNER, + .fops = &rtrack2_fops, + .ioctl_ops = &rtrack2_ioctl_ops, +}; + static int __init rtrack2_init(void) { if(io==-1) diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index bb8b1c9107b..75b68a02454 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -295,12 +295,7 @@ static const struct file_operations fmi_fops = { .llseek = no_llseek, }; -static struct video_device fmi_radio= -{ - .owner = THIS_MODULE, - .name = "SF16FMx radio", - .type = VID_TYPE_TUNER, - .fops = &fmi_fops, +static const struct v4l2_ioctl_ops fmi_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -315,6 +310,14 @@ static struct video_device fmi_radio= .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device fmi_radio = { + .owner = THIS_MODULE, + .name = "SF16FMx radio", + .type = VID_TYPE_TUNER, + .fops = &fmi_fops, + .ioctl_ops = &fmi_ioctl_ops, +}; + /* ladis: this is my card. does any other types exist? */ static struct isapnp_device_id id_table[] __devinitdata = { { ISAPNP_ANY_ID, ISAPNP_ANY_ID, diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index 9fa025b704c..5ffddce8001 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -411,12 +411,7 @@ static const struct file_operations fmr2_fops = { .llseek = no_llseek, }; -static struct video_device fmr2_radio= -{ - .owner = THIS_MODULE, - .name = "SF16FMR2 radio", - . type = VID_TYPE_TUNER, - .fops = &fmr2_fops, +static const struct v4l2_ioctl_ops fmr2_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -431,6 +426,14 @@ static struct video_device fmr2_radio= .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device fmr2_radio = { + .owner = THIS_MODULE, + .name = "SF16FMR2 radio", + .type = VID_TYPE_TUNER, + .fops = &fmr2_fops, + .ioctl_ops = &fmr2_ioctl_ops, +}; + static int __init fmr2_init(void) { fmr2_unit.port = io; diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index 33361218017..b829c67ecf0 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c @@ -1586,15 +1586,7 @@ done: return retval; } - -/* - * si470x_viddev_tamples - video device interface - */ -static struct video_device si470x_viddev_template = { - .fops = &si470x_fops, - .name = DRIVER_NAME, - .type = VID_TYPE_TUNER, - .release = video_device_release, +static const struct v4l2_ioctl_ops si470x_ioctl_ops = { .vidioc_querycap = si470x_vidioc_querycap, .vidioc_g_input = si470x_vidioc_g_input, .vidioc_s_input = si470x_vidioc_s_input, @@ -1608,6 +1600,17 @@ static struct video_device si470x_viddev_template = { .vidioc_g_frequency = si470x_vidioc_g_frequency, .vidioc_s_frequency = si470x_vidioc_s_frequency, .vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek, +}; + +/* + * si470x_viddev_tamples - video device interface + */ +static struct video_device si470x_viddev_template = { + .fops = &si470x_fops, + .ioctl_ops = &si470x_ioctl_ops, + .name = DRIVER_NAME, + .type = VID_TYPE_TUNER, + .release = video_device_release, .owner = THIS_MODULE, }; diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index a9914dbcf49..3a67471f999 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -367,12 +367,7 @@ static const struct file_operations terratec_fops = { .llseek = no_llseek, }; -static struct video_device terratec_radio= -{ - .owner = THIS_MODULE, - .name = "TerraTec ActiveRadio", - .type = VID_TYPE_TUNER, - .fops = &terratec_fops, +static const struct v4l2_ioctl_ops terratec_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -387,6 +382,14 @@ static struct video_device terratec_radio= .vidioc_s_input = vidioc_s_input, }; +static struct video_device terratec_radio = { + .owner = THIS_MODULE, + .name = "TerraTec ActiveRadio", + .type = VID_TYPE_TUNER, + .fops = &terratec_fops, + .ioctl_ops = &terratec_ioctl_ops, +}; + static int __init terratec_init(void) { if(io==-1) diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index 560c49481a2..e3340018091 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c @@ -347,12 +347,7 @@ static const struct file_operations trust_fops = { .llseek = no_llseek, }; -static struct video_device trust_radio= -{ - .owner = THIS_MODULE, - .name = "Trust FM Radio", - .type = VID_TYPE_TUNER, - .fops = &trust_fops, +static const struct v4l2_ioctl_ops trust_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -367,6 +362,14 @@ static struct video_device trust_radio= .vidioc_s_input = vidioc_s_input, }; +static struct video_device trust_radio = { + .owner = THIS_MODULE, + .name = "Trust FM Radio", + .type = VID_TYPE_TUNER, + .fops = &trust_fops, + .ioctl_ops = &trust_ioctl_ops, +}; + static int __init trust_init(void) { if(io == -1) { diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c index 023d6f3c751..48b5d2bc627 100644 --- a/drivers/media/radio/radio-typhoon.c +++ b/drivers/media/radio/radio-typhoon.c @@ -345,12 +345,7 @@ static const struct file_operations typhoon_fops = { .llseek = no_llseek, }; -static struct video_device typhoon_radio = -{ - .owner = THIS_MODULE, - .name = "Typhoon Radio", - .type = VID_TYPE_TUNER, - .fops = &typhoon_fops, +static const struct v4l2_ioctl_ops typhoon_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -365,6 +360,14 @@ static struct video_device typhoon_radio = .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device typhoon_radio = { + .owner = THIS_MODULE, + .name = "Typhoon Radio", + .type = VID_TYPE_TUNER, + .fops = &typhoon_fops, + .ioctl_ops = &typhoon_ioctl_ops, +}; + #ifdef CONFIG_RADIO_TYPHOON_PROC_FS static int typhoon_proc_show(struct seq_file *m, void *v) diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index cf0355bb6ef..c60344326cd 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c @@ -408,12 +408,7 @@ static const struct file_operations zoltrix_fops = .llseek = no_llseek, }; -static struct video_device zoltrix_radio = -{ - .owner = THIS_MODULE, - .name = "Zoltrix Radio Plus", - .type = VID_TYPE_TUNER, - .fops = &zoltrix_fops, +static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -428,6 +423,14 @@ static struct video_device zoltrix_radio = .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device zoltrix_radio = { + .owner = THIS_MODULE, + .name = "Zoltrix Radio Plus", + .type = VID_TYPE_TUNER, + .fops = &zoltrix_fops, + .ioctl_ops = &zoltrix_ioctl_ops, +}; + static int __init zoltrix_init(void) { if (io == -1) { diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 33c72055447..dfa399da587 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -3358,10 +3358,7 @@ static const struct file_operations bttv_fops = .poll = bttv_poll, }; -static struct video_device bttv_video_template = -{ - .fops = &bttv_fops, - .minor = -1, +static const struct v4l2_ioctl_ops bttv_ioctl_ops = { .vidioc_querycap = bttv_querycap, .vidioc_enum_fmt_vid_cap = bttv_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = bttv_g_fmt_vid_cap, @@ -3412,8 +3409,14 @@ static struct video_device bttv_video_template = .vidioc_g_register = bttv_g_register, .vidioc_s_register = bttv_s_register, #endif - .tvnorms = BTTV_NORMS, - .current_norm = V4L2_STD_PAL, +}; + +static struct video_device bttv_video_template = { + .fops = &bttv_fops, + .minor = -1, + .ioctl_ops = &bttv_ioctl_ops, + .tvnorms = BTTV_NORMS, + .current_norm = V4L2_STD_PAL, }; /* ----------------------------------------------------------------------- */ @@ -3636,10 +3639,7 @@ static const struct file_operations radio_fops = .poll = radio_poll, }; -static struct video_device radio_template = -{ - .fops = &radio_fops, - .minor = -1, +static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_querycap = radio_querycap, .vidioc_g_tuner = radio_g_tuner, .vidioc_enum_input = radio_enum_input, @@ -3656,6 +3656,12 @@ static struct video_device radio_template = .vidioc_s_frequency = bttv_s_frequency, }; +static struct video_device radio_template = { + .fops = &radio_fops, + .minor = -1, + .ioctl_ops = &radio_ioctl_ops, +}; + /* ----------------------------------------------------------------------- */ /* some debug code */ diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 302c57f151c..4bbea458d0c 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -1769,17 +1769,7 @@ static const struct file_operations cafe_v4l_fops = { .llseek = no_llseek, }; -static struct video_device cafe_v4l_template = { - .name = "cafe", - .type = VFL_TYPE_GRABBER, - .type2 = VID_TYPE_CAPTURE, - .minor = -1, /* Get one dynamically */ - .tvnorms = V4L2_STD_NTSC_M, - .current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */ - - .fops = &cafe_v4l_fops, - .release = cafe_v4l_dev_release, - +static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = { .vidioc_querycap = cafe_vidioc_querycap, .vidioc_enum_fmt_vid_cap = cafe_vidioc_enum_fmt_vid_cap, .vidioc_try_fmt_vid_cap = cafe_vidioc_try_fmt_vid_cap, @@ -1802,6 +1792,19 @@ static struct video_device cafe_v4l_template = { .vidioc_s_parm = cafe_vidioc_s_parm, }; +static struct video_device cafe_v4l_template = { + .name = "cafe", + .type = VFL_TYPE_GRABBER, + .type2 = VID_TYPE_CAPTURE, + .minor = -1, /* Get one dynamically */ + .tvnorms = V4L2_STD_NTSC_M, + .current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */ + + .fops = &cafe_v4l_fops, + .ioctl_ops = &cafe_v4l_ioctl_ops, + .release = cafe_v4l_dev_release, +}; + diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 0d74e59e503..a7f839631d6 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -787,50 +787,54 @@ int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return res; } -void cx18_set_funcs(struct video_device *vdev) -{ - vdev->vidioc_querycap = cx18_querycap; - vdev->vidioc_g_priority = cx18_g_priority; - vdev->vidioc_s_priority = cx18_s_priority; - vdev->vidioc_s_audio = cx18_s_audio; - vdev->vidioc_g_audio = cx18_g_audio; - vdev->vidioc_enumaudio = cx18_enumaudio; - vdev->vidioc_enum_input = cx18_enum_input; - vdev->vidioc_cropcap = cx18_cropcap; - vdev->vidioc_s_crop = cx18_s_crop; - vdev->vidioc_g_crop = cx18_g_crop; - vdev->vidioc_g_input = cx18_g_input; - vdev->vidioc_s_input = cx18_s_input; - vdev->vidioc_g_frequency = cx18_g_frequency; - vdev->vidioc_s_frequency = cx18_s_frequency; - vdev->vidioc_s_tuner = cx18_s_tuner; - vdev->vidioc_g_tuner = cx18_g_tuner; - vdev->vidioc_g_enc_index = cx18_g_enc_index; - vdev->vidioc_g_std = cx18_g_std; - vdev->vidioc_s_std = cx18_s_std; - vdev->vidioc_log_status = cx18_log_status; - vdev->vidioc_enum_fmt_vid_cap = cx18_enum_fmt_vid_cap; - vdev->vidioc_encoder_cmd = cx18_encoder_cmd; - vdev->vidioc_try_encoder_cmd = cx18_try_encoder_cmd; - vdev->vidioc_g_fmt_vid_cap = cx18_g_fmt_vid_cap; - vdev->vidioc_g_fmt_vbi_cap = cx18_g_fmt_vbi_cap; - vdev->vidioc_g_fmt_sliced_vbi_cap = cx18_g_fmt_sliced_vbi_cap; - vdev->vidioc_s_fmt_vid_cap = cx18_s_fmt_vid_cap; - vdev->vidioc_s_fmt_vbi_cap = cx18_s_fmt_vbi_cap; - vdev->vidioc_s_fmt_sliced_vbi_cap = cx18_s_fmt_sliced_vbi_cap; - vdev->vidioc_try_fmt_vid_cap = cx18_try_fmt_vid_cap; - vdev->vidioc_try_fmt_vbi_cap = cx18_try_fmt_vbi_cap; - vdev->vidioc_try_fmt_sliced_vbi_cap = cx18_try_fmt_sliced_vbi_cap; - vdev->vidioc_g_sliced_vbi_cap = cx18_g_sliced_vbi_cap; - vdev->vidioc_g_chip_ident = cx18_g_chip_ident; +static const struct v4l2_ioctl_ops cx18_ioctl_ops = { + .vidioc_querycap = cx18_querycap, + .vidioc_g_priority = cx18_g_priority, + .vidioc_s_priority = cx18_s_priority, + .vidioc_s_audio = cx18_s_audio, + .vidioc_g_audio = cx18_g_audio, + .vidioc_enumaudio = cx18_enumaudio, + .vidioc_enum_input = cx18_enum_input, + .vidioc_cropcap = cx18_cropcap, + .vidioc_s_crop = cx18_s_crop, + .vidioc_g_crop = cx18_g_crop, + .vidioc_g_input = cx18_g_input, + .vidioc_s_input = cx18_s_input, + .vidioc_g_frequency = cx18_g_frequency, + .vidioc_s_frequency = cx18_s_frequency, + .vidioc_s_tuner = cx18_s_tuner, + .vidioc_g_tuner = cx18_g_tuner, + .vidioc_g_enc_index = cx18_g_enc_index, + .vidioc_g_std = cx18_g_std, + .vidioc_s_std = cx18_s_std, + .vidioc_log_status = cx18_log_status, + .vidioc_enum_fmt_vid_cap = cx18_enum_fmt_vid_cap, + .vidioc_encoder_cmd = cx18_encoder_cmd, + .vidioc_try_encoder_cmd = cx18_try_encoder_cmd, + .vidioc_g_fmt_vid_cap = cx18_g_fmt_vid_cap, + .vidioc_g_fmt_vbi_cap = cx18_g_fmt_vbi_cap, + .vidioc_g_fmt_sliced_vbi_cap = cx18_g_fmt_sliced_vbi_cap, + .vidioc_s_fmt_vid_cap = cx18_s_fmt_vid_cap, + .vidioc_s_fmt_vbi_cap = cx18_s_fmt_vbi_cap, + .vidioc_s_fmt_sliced_vbi_cap = cx18_s_fmt_sliced_vbi_cap, + .vidioc_try_fmt_vid_cap = cx18_try_fmt_vid_cap, + .vidioc_try_fmt_vbi_cap = cx18_try_fmt_vbi_cap, + .vidioc_try_fmt_sliced_vbi_cap = cx18_try_fmt_sliced_vbi_cap, + .vidioc_g_sliced_vbi_cap = cx18_g_sliced_vbi_cap, + .vidioc_g_chip_ident = cx18_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG - vdev->vidioc_g_register = cx18_g_register; - vdev->vidioc_s_register = cx18_s_register; + .vidioc_g_register = cx18_g_register, + .vidioc_s_register = cx18_s_register, #endif - vdev->vidioc_default = cx18_default; - vdev->vidioc_queryctrl = cx18_queryctrl; - vdev->vidioc_querymenu = cx18_querymenu; - vdev->vidioc_g_ext_ctrls = cx18_g_ext_ctrls; - vdev->vidioc_s_ext_ctrls = cx18_s_ext_ctrls; - vdev->vidioc_try_ext_ctrls = cx18_try_ext_ctrls; + .vidioc_default = cx18_default, + .vidioc_queryctrl = cx18_queryctrl, + .vidioc_querymenu = cx18_querymenu, + .vidioc_g_ext_ctrls = cx18_g_ext_ctrls, + .vidioc_s_ext_ctrls = cx18_s_ext_ctrls, + .vidioc_try_ext_ctrls = cx18_try_ext_ctrls, +}; + +void cx18_set_funcs(struct video_device *vdev) +{ + vdev->ioctl_ops = &cx18_ioctl_ops; } diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index 4d0dcb06c19..9d15d8a353f 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -1700,14 +1700,7 @@ static struct file_operations mpeg_fops = { .llseek = no_llseek, }; -static struct video_device cx23885_mpeg_template = { - .name = "cx23885", - .type = VID_TYPE_CAPTURE | - VID_TYPE_TUNER | - VID_TYPE_SCALES | - VID_TYPE_MPEG_ENCODER, - .fops = &mpeg_fops, - .minor = -1, +static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_s_std = vidioc_s_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, @@ -1736,6 +1729,17 @@ static struct video_device cx23885_mpeg_template = { .vidioc_queryctrl = vidioc_queryctrl, }; +static struct video_device cx23885_mpeg_template = { + .name = "cx23885", + .type = VID_TYPE_CAPTURE | + VID_TYPE_TUNER | + VID_TYPE_SCALES | + VID_TYPE_MPEG_ENCODER, + .fops = &mpeg_fops, + .ioctl_ops = &mpeg_ioctl_ops, + .minor = -1, +}; + void cx23885_417_unregister(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __func__); diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 245712e45f6..308caa2085b 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -1434,12 +1434,7 @@ static const struct file_operations video_fops = { .llseek = no_llseek, }; -static struct video_device cx23885_vbi_template; -static struct video_device cx23885_video_template = { - .name = "cx23885-video", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES, - .fops = &video_fops, - .minor = -1, +static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1472,6 +1467,15 @@ static struct video_device cx23885_video_template = { .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif +}; + +static struct video_device cx23885_vbi_template; +static struct video_device cx23885_video_template = { + .name = "cx23885-video", + .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES, + .fops = &video_fops, + .minor = -1, + .ioctl_ops = &video_ioctl_ops, .tvnorms = CX23885_NORMS, .current_norm = V4L2_STD_NTSC_M, }; diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 4d1a461f329..55c35482089 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -1175,12 +1175,7 @@ static const struct file_operations mpeg_fops = .llseek = no_llseek, }; -static struct video_device cx8802_mpeg_template = -{ - .name = "cx8802", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES|VID_TYPE_MPEG_ENCODER, - .fops = &mpeg_fops, - .minor = -1, +static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_querymenu = vidioc_querymenu, .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, @@ -1208,6 +1203,15 @@ static struct video_device cx8802_mpeg_template = .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, .vidioc_s_std = vidioc_s_std, +}; + +static struct video_device cx8802_mpeg_template = { + .name = "cx8802", + .type = VID_TYPE_CAPTURE | VID_TYPE_TUNER | + VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER, + .fops = &mpeg_fops, + .ioctl_ops = &mpeg_ioctl_ops, + .minor = -1, .tvnorms = CX88_NORMS, .current_norm = V4L2_STD_NTSC_M, }; diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index f8cc55db9f4..24b403b238d 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1683,13 +1683,7 @@ static const struct file_operations video_fops = .llseek = no_llseek, }; -static struct video_device cx8800_vbi_template; -static struct video_device cx8800_video_template = -{ - .name = "cx8800-video", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES, - .fops = &video_fops, - .minor = -1, +static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1722,6 +1716,16 @@ static struct video_device cx8800_video_template = .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif +}; + +static struct video_device cx8800_vbi_template; + +static struct video_device cx8800_video_template = { + .name = "cx8800-video", + .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES, + .fops = &video_fops, + .minor = -1, + .ioctl_ops = &video_ioctl_ops, .tvnorms = CX88_NORMS, .current_norm = V4L2_STD_NTSC_M, }; @@ -1736,12 +1740,7 @@ static const struct file_operations radio_fops = .llseek = no_llseek, }; -static struct video_device cx8800_radio_template = -{ - .name = "cx8800-radio", - .type = VID_TYPE_TUNER, - .fops = &radio_fops, - .minor = -1, +static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_querycap = radio_querycap, .vidioc_g_tuner = radio_g_tuner, .vidioc_enum_input = radio_enum_input, @@ -1760,6 +1759,14 @@ static struct video_device cx8800_radio_template = #endif }; +static struct video_device cx8800_radio_template = { + .name = "cx8800-radio", + .type = VID_TYPE_TUNER, + .fops = &radio_fops, + .minor = -1, + .ioctl_ops = &radio_ioctl_ops, +}; + /* ----------------------------------------------------------- */ static void cx8800_unregister_video(struct cx8800_dev *dev) diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 67c62eaa5b6..fcfc7413f74 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1764,20 +1764,7 @@ static const struct file_operations em28xx_v4l_fops = { .compat_ioctl = v4l_compat_ioctl32, }; -static const struct file_operations radio_fops = { - .owner = THIS_MODULE, - .open = em28xx_v4l2_open, - .release = em28xx_v4l2_close, - .ioctl = video_ioctl2, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, -}; - -static const struct video_device em28xx_video_template = { - .fops = &em28xx_v4l_fops, - .release = video_device_release, - - .minor = -1, +static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1815,16 +1802,29 @@ static const struct video_device em28xx_video_template = { #ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf, #endif +}; + +static const struct video_device em28xx_video_template = { + .fops = &em28xx_v4l_fops, + .release = video_device_release, + .ioctl_ops = &video_ioctl_ops, + + .minor = -1, .tvnorms = V4L2_STD_ALL, .current_norm = V4L2_STD_PAL, }; -static struct video_device em28xx_radio_template = { - .name = "em28xx-radio", - .type = VID_TYPE_TUNER, - .fops = &radio_fops, - .minor = -1, +static const struct file_operations radio_fops = { + .owner = THIS_MODULE, + .open = em28xx_v4l2_open, + .release = em28xx_v4l2_close, + .ioctl = video_ioctl2, + .compat_ioctl = v4l_compat_ioctl32, + .llseek = no_llseek, +}; + +static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_querycap = radio_querycap, .vidioc_g_tuner = radio_g_tuner, .vidioc_enum_input = radio_enum_input, @@ -1843,6 +1843,14 @@ static struct video_device em28xx_radio_template = { #endif }; +static struct video_device em28xx_radio_template = { + .name = "em28xx-radio", + .type = VID_TYPE_TUNER, + .fops = &radio_fops, + .ioctl_ops = &radio_ioctl_ops, + .minor = -1, +}; + /******************************** usb interface ******************************/ diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 0f09784631a..2a416cf205a 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -1651,12 +1651,7 @@ static struct file_operations dev_fops = { .poll = dev_poll, }; -static struct video_device gspca_template = { - .name = "gspca main driver", - .type = VID_TYPE_CAPTURE, - .fops = &dev_fops, - .release = dev_release, /* mandatory */ - .minor = -1, +static const struct v4l2_ioctl_ops dev_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_dqbuf = vidioc_dqbuf, .vidioc_qbuf = vidioc_qbuf, @@ -1685,6 +1680,15 @@ static struct video_device gspca_template = { #endif }; +static struct video_device gspca_template = { + .name = "gspca main driver", + .type = VID_TYPE_CAPTURE, + .fops = &dev_fops, + .ioctl_ops = &dev_ioctl_ops, + .release = dev_release, /* mandatory */ + .minor = -1, +}; + /* * probe and create a new gspca device * diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 52e00a7f311..61030309d0a 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1842,69 +1842,73 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return res; } -void ivtv_set_funcs(struct video_device *vdev) -{ - vdev->vidioc_querycap = ivtv_querycap; - vdev->vidioc_g_priority = ivtv_g_priority; - vdev->vidioc_s_priority = ivtv_s_priority; - vdev->vidioc_s_audio = ivtv_s_audio; - vdev->vidioc_g_audio = ivtv_g_audio; - vdev->vidioc_enumaudio = ivtv_enumaudio; - vdev->vidioc_s_audout = ivtv_s_audout; - vdev->vidioc_g_audout = ivtv_g_audout; - vdev->vidioc_enum_input = ivtv_enum_input; - vdev->vidioc_enum_output = ivtv_enum_output; - vdev->vidioc_enumaudout = ivtv_enumaudout; - vdev->vidioc_cropcap = ivtv_cropcap; - vdev->vidioc_s_crop = ivtv_s_crop; - vdev->vidioc_g_crop = ivtv_g_crop; - vdev->vidioc_g_input = ivtv_g_input; - vdev->vidioc_s_input = ivtv_s_input; - vdev->vidioc_g_output = ivtv_g_output; - vdev->vidioc_s_output = ivtv_s_output; - vdev->vidioc_g_frequency = ivtv_g_frequency; - vdev->vidioc_s_frequency = ivtv_s_frequency; - vdev->vidioc_s_tuner = ivtv_s_tuner; - vdev->vidioc_g_tuner = ivtv_g_tuner; - vdev->vidioc_g_enc_index = ivtv_g_enc_index; - vdev->vidioc_g_fbuf = ivtv_g_fbuf; - vdev->vidioc_s_fbuf = ivtv_s_fbuf; - vdev->vidioc_g_std = ivtv_g_std; - vdev->vidioc_s_std = ivtv_s_std; - vdev->vidioc_overlay = ivtv_overlay; - vdev->vidioc_log_status = ivtv_log_status; - vdev->vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap; - vdev->vidioc_encoder_cmd = ivtv_encoder_cmd; - vdev->vidioc_try_encoder_cmd = ivtv_try_encoder_cmd; - vdev->vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out; - vdev->vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap; - vdev->vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap; - vdev->vidioc_g_fmt_sliced_vbi_cap = ivtv_g_fmt_sliced_vbi_cap; - vdev->vidioc_g_fmt_vid_out = ivtv_g_fmt_vid_out; - vdev->vidioc_g_fmt_vid_out_overlay = ivtv_g_fmt_vid_out_overlay; - vdev->vidioc_g_fmt_sliced_vbi_out = ivtv_g_fmt_sliced_vbi_out; - vdev->vidioc_s_fmt_vid_cap = ivtv_s_fmt_vid_cap; - vdev->vidioc_s_fmt_vbi_cap = ivtv_s_fmt_vbi_cap; - vdev->vidioc_s_fmt_sliced_vbi_cap = ivtv_s_fmt_sliced_vbi_cap; - vdev->vidioc_s_fmt_vid_out = ivtv_s_fmt_vid_out; - vdev->vidioc_s_fmt_vid_out_overlay = ivtv_s_fmt_vid_out_overlay; - vdev->vidioc_s_fmt_sliced_vbi_out = ivtv_s_fmt_sliced_vbi_out; - vdev->vidioc_try_fmt_vid_cap = ivtv_try_fmt_vid_cap; - vdev->vidioc_try_fmt_vbi_cap = ivtv_try_fmt_vbi_cap; - vdev->vidioc_try_fmt_sliced_vbi_cap = ivtv_try_fmt_sliced_vbi_cap; - vdev->vidioc_try_fmt_vid_out = ivtv_try_fmt_vid_out; - vdev->vidioc_try_fmt_vid_out_overlay = ivtv_try_fmt_vid_out_overlay; - vdev->vidioc_try_fmt_sliced_vbi_out = ivtv_try_fmt_sliced_vbi_out; - vdev->vidioc_g_sliced_vbi_cap = ivtv_g_sliced_vbi_cap; - vdev->vidioc_g_chip_ident = ivtv_g_chip_ident; +static const struct v4l2_ioctl_ops ivtv_ioctl_ops = { + .vidioc_querycap = ivtv_querycap, + .vidioc_g_priority = ivtv_g_priority, + .vidioc_s_priority = ivtv_s_priority, + .vidioc_s_audio = ivtv_s_audio, + .vidioc_g_audio = ivtv_g_audio, + .vidioc_enumaudio = ivtv_enumaudio, + .vidioc_s_audout = ivtv_s_audout, + .vidioc_g_audout = ivtv_g_audout, + .vidioc_enum_input = ivtv_enum_input, + .vidioc_enum_output = ivtv_enum_output, + .vidioc_enumaudout = ivtv_enumaudout, + .vidioc_cropcap = ivtv_cropcap, + .vidioc_s_crop = ivtv_s_crop, + .vidioc_g_crop = ivtv_g_crop, + .vidioc_g_input = ivtv_g_input, + .vidioc_s_input = ivtv_s_input, + .vidioc_g_output = ivtv_g_output, + .vidioc_s_output = ivtv_s_output, + .vidioc_g_frequency = ivtv_g_frequency, + .vidioc_s_frequency = ivtv_s_frequency, + .vidioc_s_tuner = ivtv_s_tuner, + .vidioc_g_tuner = ivtv_g_tuner, + .vidioc_g_enc_index = ivtv_g_enc_index, + .vidioc_g_fbuf = ivtv_g_fbuf, + .vidioc_s_fbuf = ivtv_s_fbuf, + .vidioc_g_std = ivtv_g_std, + .vidioc_s_std = ivtv_s_std, + .vidioc_overlay = ivtv_overlay, + .vidioc_log_status = ivtv_log_status, + .vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap, + .vidioc_encoder_cmd = ivtv_encoder_cmd, + .vidioc_try_encoder_cmd = ivtv_try_encoder_cmd, + .vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out, + .vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap, + .vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap, + .vidioc_g_fmt_sliced_vbi_cap = ivtv_g_fmt_sliced_vbi_cap, + .vidioc_g_fmt_vid_out = ivtv_g_fmt_vid_out, + .vidioc_g_fmt_vid_out_overlay = ivtv_g_fmt_vid_out_overlay, + .vidioc_g_fmt_sliced_vbi_out = ivtv_g_fmt_sliced_vbi_out, + .vidioc_s_fmt_vid_cap = ivtv_s_fmt_vid_cap, + .vidioc_s_fmt_vbi_cap = ivtv_s_fmt_vbi_cap, + .vidioc_s_fmt_sliced_vbi_cap = ivtv_s_fmt_sliced_vbi_cap, + .vidioc_s_fmt_vid_out = ivtv_s_fmt_vid_out, + .vidioc_s_fmt_vid_out_overlay = ivtv_s_fmt_vid_out_overlay, + .vidioc_s_fmt_sliced_vbi_out = ivtv_s_fmt_sliced_vbi_out, + .vidioc_try_fmt_vid_cap = ivtv_try_fmt_vid_cap, + .vidioc_try_fmt_vbi_cap = ivtv_try_fmt_vbi_cap, + .vidioc_try_fmt_sliced_vbi_cap = ivtv_try_fmt_sliced_vbi_cap, + .vidioc_try_fmt_vid_out = ivtv_try_fmt_vid_out, + .vidioc_try_fmt_vid_out_overlay = ivtv_try_fmt_vid_out_overlay, + .vidioc_try_fmt_sliced_vbi_out = ivtv_try_fmt_sliced_vbi_out, + .vidioc_g_sliced_vbi_cap = ivtv_g_sliced_vbi_cap, + .vidioc_g_chip_ident = ivtv_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG - vdev->vidioc_g_register = ivtv_g_register; - vdev->vidioc_s_register = ivtv_s_register; + .vidioc_g_register = ivtv_g_register, + .vidioc_s_register = ivtv_s_register, #endif - vdev->vidioc_default = ivtv_default; - vdev->vidioc_queryctrl = ivtv_queryctrl; - vdev->vidioc_querymenu = ivtv_querymenu; - vdev->vidioc_g_ext_ctrls = ivtv_g_ext_ctrls; - vdev->vidioc_s_ext_ctrls = ivtv_s_ext_ctrls; - vdev->vidioc_try_ext_ctrls = ivtv_try_ext_ctrls; + .vidioc_default = ivtv_default, + .vidioc_queryctrl = ivtv_queryctrl, + .vidioc_querymenu = ivtv_querymenu, + .vidioc_g_ext_ctrls = ivtv_g_ext_ctrls, + .vidioc_s_ext_ctrls = ivtv_s_ext_ctrls, + .vidioc_try_ext_ctrls = ivtv_try_ext_ctrls, +}; + +void ivtv_set_funcs(struct video_device *vdev) +{ + vdev->ioctl_ops = &ivtv_ioctl_ops; } diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index a1fb9874fdc..fd16ef0a586 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -1698,13 +1698,7 @@ static const struct file_operations meye_fops = { .llseek = no_llseek, }; -static struct video_device meye_template = { - .owner = THIS_MODULE, - .name = "meye", - .type = VID_TYPE_CAPTURE, - .fops = &meye_fops, - .release = video_device_release, - .minor = -1, +static const struct v4l2_ioctl_ops meye_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, @@ -1725,6 +1719,16 @@ static struct video_device meye_template = { .vidioc_default = vidioc_default, }; +static struct video_device meye_template = { + .owner = THIS_MODULE, + .name = "meye", + .type = VID_TYPE_CAPTURE, + .fops = &meye_fops, + .ioctl_ops = &meye_ioctl_ops, + .release = video_device_release, + .minor = -1, +}; + #ifdef CONFIG_PM static int meye_suspend(struct pci_dev *pdev, pm_message_t state) { diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c index eb81915935b..2428d441fe1 100644 --- a/drivers/media/video/s2255drv.c +++ b/drivers/media/video/s2255drv.c @@ -1659,12 +1659,7 @@ static const struct file_operations s2255_fops_v4l = { .llseek = no_llseek, }; -static struct video_device template = { - .name = "s2255v", - .type = VID_TYPE_CAPTURE, - .fops = &s2255_fops_v4l, - .minor = -1, - .release = video_device_release, +static const struct v4l2_ioctl_ops s2255_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1686,6 +1681,15 @@ static struct video_device template = { #ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidioc_cgmbuf, #endif +}; + +static struct video_device template = { + .name = "s2255v", + .type = VID_TYPE_CAPTURE, + .fops = &s2255_fops_v4l, + .ioctl_ops = &s2255_ioctl_ops, + .minor = -1, + .release = video_device_release, .tvnorms = S2255_NORMS, .current_norm = V4L2_STD_NTSC_M, }; diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 3854cc29752..8b3f9516778 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -400,16 +400,7 @@ static const struct file_operations ts_fops = .llseek = no_llseek, }; -/* ----------------------------------------------------------- */ - -static struct video_device saa7134_empress_template = -{ - .name = "saa7134-empress", - .type = 0 /* FIXME */, - .type2 = 0 /* FIXME */, - .fops = &ts_fops, - .minor = -1, - +static const struct v4l2_ioctl_ops ts_ioctl_ops = { .vidioc_querycap = empress_querycap, .vidioc_enum_fmt_vid_cap = empress_enum_fmt_vid_cap, .vidioc_s_fmt_vid_cap = empress_s_fmt_vid_cap, @@ -430,6 +421,17 @@ static struct video_device saa7134_empress_template = .vidioc_querymenu = empress_querymenu, .vidioc_g_ctrl = saa7134_g_ctrl, .vidioc_s_ctrl = saa7134_s_ctrl, +}; + +/* ----------------------------------------------------------- */ + +static struct video_device saa7134_empress_template = { + .name = "saa7134-empress", + .type = 0 /* FIXME */, + .type2 = 0 /* FIXME */, + .fops = &ts_fops, + .minor = -1, + .ioctl_ops = &ts_ioctl_ops, .tvnorms = SAA7134_NORMS, .current_norm = V4L2_STD_PAL, diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 1a5137550e7..5e9cfc891be 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -2353,26 +2353,7 @@ static const struct file_operations video_fops = .llseek = no_llseek, }; -static const struct file_operations radio_fops = -{ - .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .ioctl = video_ioctl2, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, -}; - -/* ----------------------------------------------------------- */ -/* exported stuff */ - -struct video_device saa7134_video_template = -{ - .name = "saa7134-video", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER | - VID_TYPE_CLIPPING|VID_TYPE_SCALES, - .fops = &video_fops, - .minor = -1, +static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_querycap = saa7134_querycap, .vidioc_enum_fmt_vid_cap = saa7134_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = saa7134_g_fmt_vid_cap, @@ -2421,16 +2402,18 @@ struct video_device saa7134_video_template = .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif - .tvnorms = SAA7134_NORMS, - .current_norm = V4L2_STD_PAL, }; -struct video_device saa7134_radio_template = -{ - .name = "saa7134-radio", - .type = VID_TYPE_TUNER, - .fops = &radio_fops, - .minor = -1, +static const struct file_operations radio_fops = { + .owner = THIS_MODULE, + .open = video_open, + .release = video_release, + .ioctl = video_ioctl2, + .compat_ioctl = v4l_compat_ioctl32, + .llseek = no_llseek, +}; + +static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_querycap = radio_querycap, .vidioc_g_tuner = radio_g_tuner, .vidioc_enum_input = radio_enum_input, @@ -2447,6 +2430,28 @@ struct video_device saa7134_radio_template = .vidioc_s_frequency = saa7134_s_frequency, }; +/* ----------------------------------------------------------- */ +/* exported stuff */ + +struct video_device saa7134_video_template = { + .name = "saa7134-video", + .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER | + VID_TYPE_CLIPPING|VID_TYPE_SCALES, + .fops = &video_fops, + .ioctl_ops = &video_ioctl_ops, + .minor = -1, + .tvnorms = SAA7134_NORMS, + .current_norm = V4L2_STD_PAL, +}; + +struct video_device saa7134_radio_template = { + .name = "saa7134-radio", + .type = VID_TYPE_TUNER, + .fops = &radio_fops, + .ioctl_ops = &radio_ioctl_ops, + .minor = -1, +}; + int saa7134_video_init1(struct saa7134_dev *dev) { /* sanitycheck insmod options */ diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index b0174908847..9ff56145258 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -862,6 +862,35 @@ void soc_camera_device_unregister(struct soc_camera_device *icd) } EXPORT_SYMBOL(soc_camera_device_unregister); +static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { + .vidioc_querycap = soc_camera_querycap, + .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap, + .vidioc_enum_input = soc_camera_enum_input, + .vidioc_g_input = soc_camera_g_input, + .vidioc_s_input = soc_camera_s_input, + .vidioc_s_std = soc_camera_s_std, + .vidioc_reqbufs = soc_camera_reqbufs, + .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap, + .vidioc_querybuf = soc_camera_querybuf, + .vidioc_qbuf = soc_camera_qbuf, + .vidioc_dqbuf = soc_camera_dqbuf, + .vidioc_streamon = soc_camera_streamon, + .vidioc_streamoff = soc_camera_streamoff, + .vidioc_queryctrl = soc_camera_queryctrl, + .vidioc_g_ctrl = soc_camera_g_ctrl, + .vidioc_s_ctrl = soc_camera_s_ctrl, + .vidioc_cropcap = soc_camera_cropcap, + .vidioc_g_crop = soc_camera_g_crop, + .vidioc_s_crop = soc_camera_s_crop, + .vidioc_g_chip_ident = soc_camera_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = soc_camera_g_register, + .vidioc_s_register = soc_camera_s_register, +#endif +}; + int soc_camera_video_start(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); @@ -882,35 +911,10 @@ int soc_camera_video_start(struct soc_camera_device *icd) vdev->type = VID_TYPE_CAPTURE; vdev->current_norm = V4L2_STD_UNKNOWN; vdev->fops = &soc_camera_fops; + vdev->ioctl_ops = &soc_camera_ioctl_ops; vdev->release = video_device_release; vdev->minor = -1; vdev->tvnorms = V4L2_STD_UNKNOWN, - vdev->vidioc_querycap = soc_camera_querycap; - vdev->vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap; - vdev->vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap; - vdev->vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap; - vdev->vidioc_enum_input = soc_camera_enum_input; - vdev->vidioc_g_input = soc_camera_g_input; - vdev->vidioc_s_input = soc_camera_s_input; - vdev->vidioc_s_std = soc_camera_s_std; - vdev->vidioc_reqbufs = soc_camera_reqbufs; - vdev->vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap; - vdev->vidioc_querybuf = soc_camera_querybuf; - vdev->vidioc_qbuf = soc_camera_qbuf; - vdev->vidioc_dqbuf = soc_camera_dqbuf; - vdev->vidioc_streamon = soc_camera_streamon; - vdev->vidioc_streamoff = soc_camera_streamoff; - vdev->vidioc_queryctrl = soc_camera_queryctrl; - vdev->vidioc_g_ctrl = soc_camera_g_ctrl; - vdev->vidioc_s_ctrl = soc_camera_s_ctrl; - vdev->vidioc_cropcap = soc_camera_cropcap; - vdev->vidioc_g_crop = soc_camera_g_crop; - vdev->vidioc_s_crop = soc_camera_s_crop; - vdev->vidioc_g_chip_ident = soc_camera_g_chip_ident; -#ifdef CONFIG_VIDEO_ADV_DEBUG - vdev->vidioc_g_register = soc_camera_g_register; - vdev->vidioc_s_register = soc_camera_s_register; -#endif icd->current_fmt = &icd->formats[0]; diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index 20028aeb842..8d5fa95ad95 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -1328,20 +1328,7 @@ static struct file_operations v4l_stk_fops = { .llseek = no_llseek }; -static void stk_v4l_dev_release(struct video_device *vd) -{ -} - -static struct video_device stk_v4l_data = { - .name = "stkwebcam", - .type = VFL_TYPE_GRABBER, - .type2 = VID_TYPE_CAPTURE, - .minor = -1, - .tvnorms = V4L2_STD_UNKNOWN, - .current_norm = V4L2_STD_UNKNOWN, - .fops = &v4l_stk_fops, - .release = stk_v4l_dev_release, - +static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = { .vidioc_querycap = stk_vidioc_querycap, .vidioc_enum_fmt_vid_cap = stk_vidioc_enum_fmt_vid_cap, .vidioc_try_fmt_vid_cap = stk_vidioc_try_fmt_vid_cap, @@ -1363,6 +1350,22 @@ static struct video_device stk_v4l_data = { .vidioc_g_parm = stk_vidioc_g_parm, }; +static void stk_v4l_dev_release(struct video_device *vd) +{ +} + +static struct video_device stk_v4l_data = { + .name = "stkwebcam", + .type = VFL_TYPE_GRABBER, + .type2 = VID_TYPE_CAPTURE, + .minor = -1, + .tvnorms = V4L2_STD_UNKNOWN, + .current_norm = V4L2_STD_UNKNOWN, + .fops = &v4l_stk_fops, + .ioctl_ops = &v4l_stk_ioctl_ops, + .release = stk_v4l_dev_release, +}; + static int stk_register_video_device(struct stk_camera *dev) { diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 5984c756203..7eccdc1ea2d 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -1370,13 +1370,8 @@ static const struct file_operations usbvision_fops = { /* .poll = video_poll, */ .compat_ioctl = v4l_compat_ioctl32, }; -static struct video_device usbvision_video_template = { - .owner = THIS_MODULE, - .type = VID_TYPE_TUNER | VID_TYPE_CAPTURE, - .fops = &usbvision_fops, - .name = "usbvision-video", - .release = video_device_release, - .minor = -1, + +static const struct v4l2_ioctl_ops usbvision_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1408,6 +1403,16 @@ static struct video_device usbvision_video_template = { .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif +}; + +static struct video_device usbvision_video_template = { + .owner = THIS_MODULE, + .type = VID_TYPE_TUNER | VID_TYPE_CAPTURE, + .fops = &usbvision_fops, + .ioctl_ops = &usbvision_ioctl_ops, + .name = "usbvision-video", + .release = video_device_release, + .minor = -1, .tvnorms = USBVISION_NORMS, .current_norm = V4L2_STD_PAL }; @@ -1423,14 +1428,7 @@ static const struct file_operations usbvision_radio_fops = { .compat_ioctl = v4l_compat_ioctl32, }; -static struct video_device usbvision_radio_template= -{ - .owner = THIS_MODULE, - .type = VID_TYPE_TUNER, - .fops = &usbvision_radio_fops, - .name = "usbvision-radio", - .release = video_device_release, - .minor = -1, +static const struct v4l2_ioctl_ops usbvision_radio_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, @@ -1444,6 +1442,16 @@ static struct video_device usbvision_radio_template= .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, +}; + +static struct video_device usbvision_radio_template = { + .owner = THIS_MODULE, + .type = VID_TYPE_TUNER, + .fops = &usbvision_radio_fops, + .name = "usbvision-radio", + .release = video_device_release, + .minor = -1, + .ioctl_ops = &usbvision_radio_ioctl_ops, .tvnorms = USBVISION_NORMS, .current_norm = V4L2_STD_PAL diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 56a4fdee916..fdfe7739c96 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -579,43 +579,46 @@ static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) return 1; } -static int check_fmt(struct video_device *vfd, enum v4l2_buf_type type) +static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) { + if (ops == NULL) + return -EINVAL; + switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (vfd->vidioc_try_fmt_vid_cap) + if (ops->vidioc_try_fmt_vid_cap) return 0; break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_try_fmt_vid_overlay) + if (ops->vidioc_try_fmt_vid_overlay) return 0; break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (vfd->vidioc_try_fmt_vid_out) + if (ops->vidioc_try_fmt_vid_out) return 0; break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_try_fmt_vid_out_overlay) + if (ops->vidioc_try_fmt_vid_out_overlay) return 0; break; case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_try_fmt_vbi_cap) + if (ops->vidioc_try_fmt_vbi_cap) return 0; break; case V4L2_BUF_TYPE_VBI_OUTPUT: - if (vfd->vidioc_try_fmt_vbi_out) + if (ops->vidioc_try_fmt_vbi_out) return 0; break; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (vfd->vidioc_try_fmt_sliced_vbi_cap) + if (ops->vidioc_try_fmt_sliced_vbi_cap) return 0; break; case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (vfd->vidioc_try_fmt_sliced_vbi_out) + if (ops->vidioc_try_fmt_sliced_vbi_out) return 0; break; case V4L2_BUF_TYPE_PRIVATE: - if (vfd->vidioc_try_fmt_type_private) + if (ops->vidioc_try_fmt_type_private) return 0; break; } @@ -626,6 +629,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) { struct video_device *vfd = video_devdata(file); + const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; void *fh = file->private_data; int ret = -EINVAL; @@ -635,6 +639,12 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, printk(KERN_CONT "\n"); } + if (ops == NULL) { + printk(KERN_WARNING "videodev: \"%s\" has no ioctl_ops.\n", + vfd->name); + return -EINVAL; + } + #ifdef CONFIG_VIDEO_V4L1_COMPAT /*********************************************************** Handles calls to the obsoleted V4L1 API @@ -648,9 +658,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, memset(p, 0, sizeof(*p)); - if (!vfd->vidiocgmbuf) + if (!ops->vidiocgmbuf) return ret; - ret = vfd->vidiocgmbuf(file, fh, p); + ret = ops->vidiocgmbuf(file, fh, p); if (!ret) dbgarg(cmd, "size=%d, frames=%d, offsets=0x%08lx\n", p->size, p->frames, @@ -676,10 +686,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_capability *cap = (struct v4l2_capability *)arg; memset(cap, 0, sizeof(*cap)); - if (!vfd->vidioc_querycap) + if (!ops->vidioc_querycap) break; - ret = vfd->vidioc_querycap(file, fh, cap); + ret = ops->vidioc_querycap(file, fh, cap); if (!ret) dbgarg(cmd, "driver=%s, card=%s, bus=%s, " "version=0x%08x, " @@ -695,9 +705,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { enum v4l2_priority *p = arg; - if (!vfd->vidioc_g_priority) + if (!ops->vidioc_g_priority) break; - ret = vfd->vidioc_g_priority(file, fh, p); + ret = ops->vidioc_g_priority(file, fh, p); if (!ret) dbgarg(cmd, "priority is %d\n", *p); break; @@ -706,10 +716,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { enum v4l2_priority *p = arg; - if (!vfd->vidioc_s_priority) + if (!ops->vidioc_s_priority) break; dbgarg(cmd, "setting priority to %d\n", *p); - ret = vfd->vidioc_s_priority(file, fh, *p); + ret = ops->vidioc_s_priority(file, fh, *p); break; } @@ -728,12 +738,12 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (vfd->vidioc_enum_fmt_vid_cap) - ret = vfd->vidioc_enum_fmt_vid_cap(file, fh, f); + if (ops->vidioc_enum_fmt_vid_cap) + ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_enum_fmt_vid_overlay) - ret = vfd->vidioc_enum_fmt_vid_overlay(file, + if (ops->vidioc_enum_fmt_vid_overlay) + ret = ops->vidioc_enum_fmt_vid_overlay(file, fh, f); break; #if 1 @@ -742,19 +752,19 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, * it though, so just warn that this is deprecated and will be * removed in the near future. */ case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_enum_fmt_vbi_cap) { + if (ops->vidioc_enum_fmt_vbi_cap) { printk(KERN_WARNING "vidioc_enum_fmt_vbi_cap will be removed in 2.6.28!\n"); - ret = vfd->vidioc_enum_fmt_vbi_cap(file, fh, f); + ret = ops->vidioc_enum_fmt_vbi_cap(file, fh, f); } break; #endif case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (vfd->vidioc_enum_fmt_vid_out) - ret = vfd->vidioc_enum_fmt_vid_out(file, fh, f); + if (ops->vidioc_enum_fmt_vid_out) + ret = ops->vidioc_enum_fmt_vid_out(file, fh, f); break; case V4L2_BUF_TYPE_PRIVATE: - if (vfd->vidioc_enum_fmt_type_private) - ret = vfd->vidioc_enum_fmt_type_private(file, + if (ops->vidioc_enum_fmt_type_private) + ret = ops->vidioc_enum_fmt_type_private(file, fh, f); break; default: @@ -782,48 +792,48 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (vfd->vidioc_g_fmt_vid_cap) - ret = vfd->vidioc_g_fmt_vid_cap(file, fh, f); + if (ops->vidioc_g_fmt_vid_cap) + ret = ops->vidioc_g_fmt_vid_cap(file, fh, f); if (!ret) v4l_print_pix_fmt(vfd, &f->fmt.pix); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_g_fmt_vid_overlay) - ret = vfd->vidioc_g_fmt_vid_overlay(file, + if (ops->vidioc_g_fmt_vid_overlay) + ret = ops->vidioc_g_fmt_vid_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (vfd->vidioc_g_fmt_vid_out) - ret = vfd->vidioc_g_fmt_vid_out(file, fh, f); + if (ops->vidioc_g_fmt_vid_out) + ret = ops->vidioc_g_fmt_vid_out(file, fh, f); if (!ret) v4l_print_pix_fmt(vfd, &f->fmt.pix); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_g_fmt_vid_out_overlay) - ret = vfd->vidioc_g_fmt_vid_out_overlay(file, + if (ops->vidioc_g_fmt_vid_out_overlay) + ret = ops->vidioc_g_fmt_vid_out_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_g_fmt_vbi_cap) - ret = vfd->vidioc_g_fmt_vbi_cap(file, fh, f); + if (ops->vidioc_g_fmt_vbi_cap) + ret = ops->vidioc_g_fmt_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_VBI_OUTPUT: - if (vfd->vidioc_g_fmt_vbi_out) - ret = vfd->vidioc_g_fmt_vbi_out(file, fh, f); + if (ops->vidioc_g_fmt_vbi_out) + ret = ops->vidioc_g_fmt_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (vfd->vidioc_g_fmt_sliced_vbi_cap) - ret = vfd->vidioc_g_fmt_sliced_vbi_cap(file, + if (ops->vidioc_g_fmt_sliced_vbi_cap) + ret = ops->vidioc_g_fmt_sliced_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (vfd->vidioc_g_fmt_sliced_vbi_out) - ret = vfd->vidioc_g_fmt_sliced_vbi_out(file, + if (ops->vidioc_g_fmt_sliced_vbi_out) + ret = ops->vidioc_g_fmt_sliced_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_PRIVATE: - if (vfd->vidioc_g_fmt_type_private) - ret = vfd->vidioc_g_fmt_type_private(file, + if (ops->vidioc_g_fmt_type_private) + ret = ops->vidioc_g_fmt_type_private(file, fh, f); break; } @@ -840,45 +850,45 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: v4l_print_pix_fmt(vfd, &f->fmt.pix); - if (vfd->vidioc_s_fmt_vid_cap) - ret = vfd->vidioc_s_fmt_vid_cap(file, fh, f); + if (ops->vidioc_s_fmt_vid_cap) + ret = ops->vidioc_s_fmt_vid_cap(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_s_fmt_vid_overlay) - ret = vfd->vidioc_s_fmt_vid_overlay(file, + if (ops->vidioc_s_fmt_vid_overlay) + ret = ops->vidioc_s_fmt_vid_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: v4l_print_pix_fmt(vfd, &f->fmt.pix); - if (vfd->vidioc_s_fmt_vid_out) - ret = vfd->vidioc_s_fmt_vid_out(file, fh, f); + if (ops->vidioc_s_fmt_vid_out) + ret = ops->vidioc_s_fmt_vid_out(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_s_fmt_vid_out_overlay) - ret = vfd->vidioc_s_fmt_vid_out_overlay(file, + if (ops->vidioc_s_fmt_vid_out_overlay) + ret = ops->vidioc_s_fmt_vid_out_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_s_fmt_vbi_cap) - ret = vfd->vidioc_s_fmt_vbi_cap(file, fh, f); + if (ops->vidioc_s_fmt_vbi_cap) + ret = ops->vidioc_s_fmt_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_VBI_OUTPUT: - if (vfd->vidioc_s_fmt_vbi_out) - ret = vfd->vidioc_s_fmt_vbi_out(file, fh, f); + if (ops->vidioc_s_fmt_vbi_out) + ret = ops->vidioc_s_fmt_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (vfd->vidioc_s_fmt_sliced_vbi_cap) - ret = vfd->vidioc_s_fmt_sliced_vbi_cap(file, + if (ops->vidioc_s_fmt_sliced_vbi_cap) + ret = ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (vfd->vidioc_s_fmt_sliced_vbi_out) - ret = vfd->vidioc_s_fmt_sliced_vbi_out(file, + if (ops->vidioc_s_fmt_sliced_vbi_out) + ret = ops->vidioc_s_fmt_sliced_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_PRIVATE: - if (vfd->vidioc_s_fmt_type_private) - ret = vfd->vidioc_s_fmt_type_private(file, + if (ops->vidioc_s_fmt_type_private) + ret = ops->vidioc_s_fmt_type_private(file, fh, f); break; } @@ -893,48 +903,48 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, v4l2_type_names)); switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (vfd->vidioc_try_fmt_vid_cap) - ret = vfd->vidioc_try_fmt_vid_cap(file, fh, f); + if (ops->vidioc_try_fmt_vid_cap) + ret = ops->vidioc_try_fmt_vid_cap(file, fh, f); if (!ret) v4l_print_pix_fmt(vfd, &f->fmt.pix); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_try_fmt_vid_overlay) - ret = vfd->vidioc_try_fmt_vid_overlay(file, + if (ops->vidioc_try_fmt_vid_overlay) + ret = ops->vidioc_try_fmt_vid_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (vfd->vidioc_try_fmt_vid_out) - ret = vfd->vidioc_try_fmt_vid_out(file, fh, f); + if (ops->vidioc_try_fmt_vid_out) + ret = ops->vidioc_try_fmt_vid_out(file, fh, f); if (!ret) v4l_print_pix_fmt(vfd, &f->fmt.pix); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_try_fmt_vid_out_overlay) - ret = vfd->vidioc_try_fmt_vid_out_overlay(file, + if (ops->vidioc_try_fmt_vid_out_overlay) + ret = ops->vidioc_try_fmt_vid_out_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_try_fmt_vbi_cap) - ret = vfd->vidioc_try_fmt_vbi_cap(file, fh, f); + if (ops->vidioc_try_fmt_vbi_cap) + ret = ops->vidioc_try_fmt_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_VBI_OUTPUT: - if (vfd->vidioc_try_fmt_vbi_out) - ret = vfd->vidioc_try_fmt_vbi_out(file, fh, f); + if (ops->vidioc_try_fmt_vbi_out) + ret = ops->vidioc_try_fmt_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (vfd->vidioc_try_fmt_sliced_vbi_cap) - ret = vfd->vidioc_try_fmt_sliced_vbi_cap(file, + if (ops->vidioc_try_fmt_sliced_vbi_cap) + ret = ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (vfd->vidioc_try_fmt_sliced_vbi_out) - ret = vfd->vidioc_try_fmt_sliced_vbi_out(file, + if (ops->vidioc_try_fmt_sliced_vbi_out) + ret = ops->vidioc_try_fmt_sliced_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_PRIVATE: - if (vfd->vidioc_try_fmt_type_private) - ret = vfd->vidioc_try_fmt_type_private(file, + if (ops->vidioc_try_fmt_type_private) + ret = ops->vidioc_try_fmt_type_private(file, fh, f); break; } @@ -949,13 +959,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_requestbuffers *p = arg; - if (!vfd->vidioc_reqbufs) + if (!ops->vidioc_reqbufs) break; - ret = check_fmt(vfd, p->type); + ret = check_fmt(ops, p->type); if (ret) break; - ret = vfd->vidioc_reqbufs(file, fh, p); + ret = ops->vidioc_reqbufs(file, fh, p); dbgarg(cmd, "count=%d, type=%s, memory=%s\n", p->count, prt_names(p->type, v4l2_type_names), @@ -966,13 +976,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_buffer *p = arg; - if (!vfd->vidioc_querybuf) + if (!ops->vidioc_querybuf) break; - ret = check_fmt(vfd, p->type); + ret = check_fmt(ops, p->type); if (ret) break; - ret = vfd->vidioc_querybuf(file, fh, p); + ret = ops->vidioc_querybuf(file, fh, p); if (!ret) dbgbuf(cmd, vfd, p); break; @@ -981,13 +991,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_buffer *p = arg; - if (!vfd->vidioc_qbuf) + if (!ops->vidioc_qbuf) break; - ret = check_fmt(vfd, p->type); + ret = check_fmt(ops, p->type); if (ret) break; - ret = vfd->vidioc_qbuf(file, fh, p); + ret = ops->vidioc_qbuf(file, fh, p); if (!ret) dbgbuf(cmd, vfd, p); break; @@ -996,13 +1006,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_buffer *p = arg; - if (!vfd->vidioc_dqbuf) + if (!ops->vidioc_dqbuf) break; - ret = check_fmt(vfd, p->type); + ret = check_fmt(ops, p->type); if (ret) break; - ret = vfd->vidioc_dqbuf(file, fh, p); + ret = ops->vidioc_dqbuf(file, fh, p); if (!ret) dbgbuf(cmd, vfd, p); break; @@ -1011,19 +1021,19 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { int *i = arg; - if (!vfd->vidioc_overlay) + if (!ops->vidioc_overlay) break; dbgarg(cmd, "value=%d\n", *i); - ret = vfd->vidioc_overlay(file, fh, *i); + ret = ops->vidioc_overlay(file, fh, *i); break; } case VIDIOC_G_FBUF: { struct v4l2_framebuffer *p = arg; - if (!vfd->vidioc_g_fbuf) + if (!ops->vidioc_g_fbuf) break; - ret = vfd->vidioc_g_fbuf(file, fh, arg); + ret = ops->vidioc_g_fbuf(file, fh, arg); if (!ret) { dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", p->capability, p->flags, @@ -1036,32 +1046,32 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_framebuffer *p = arg; - if (!vfd->vidioc_s_fbuf) + if (!ops->vidioc_s_fbuf) break; dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", p->capability, p->flags, (unsigned long)p->base); v4l_print_pix_fmt(vfd, &p->fmt); - ret = vfd->vidioc_s_fbuf(file, fh, arg); + ret = ops->vidioc_s_fbuf(file, fh, arg); break; } case VIDIOC_STREAMON: { enum v4l2_buf_type i = *(int *)arg; - if (!vfd->vidioc_streamon) + if (!ops->vidioc_streamon) break; dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); - ret = vfd->vidioc_streamon(file, fh, i); + ret = ops->vidioc_streamon(file, fh, i); break; } case VIDIOC_STREAMOFF: { enum v4l2_buf_type i = *(int *)arg; - if (!vfd->vidioc_streamoff) + if (!ops->vidioc_streamoff) break; dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); - ret = vfd->vidioc_streamoff(file, fh, i); + ret = ops->vidioc_streamoff(file, fh, i); break; } /* ---------- tv norms ---------- */ @@ -1110,8 +1120,8 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret = 0; /* Calls the specific handler */ - if (vfd->vidioc_g_std) - ret = vfd->vidioc_g_std(file, fh, id); + if (ops->vidioc_g_std) + ret = ops->vidioc_g_std(file, fh, id); else *id = vfd->current_norm; @@ -1130,8 +1140,8 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, break; /* Calls the specific handler */ - if (vfd->vidioc_s_std) - ret = vfd->vidioc_s_std(file, fh, &norm); + if (ops->vidioc_s_std) + ret = ops->vidioc_s_std(file, fh, &norm); else ret = -EINVAL; @@ -1144,9 +1154,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { v4l2_std_id *p = arg; - if (!vfd->vidioc_querystd) + if (!ops->vidioc_querystd) break; - ret = vfd->vidioc_querystd(file, fh, arg); + ret = ops->vidioc_querystd(file, fh, arg); if (!ret) dbgarg(cmd, "detected std=%08Lx\n", (unsigned long long)*p); @@ -1159,12 +1169,12 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_input *p = arg; int i = p->index; - if (!vfd->vidioc_enum_input) + if (!ops->vidioc_enum_input) break; memset(p, 0, sizeof(*p)); p->index = i; - ret = vfd->vidioc_enum_input(file, fh, p); + ret = ops->vidioc_enum_input(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, type=%d, " "audioset=%d, " @@ -1179,9 +1189,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { unsigned int *i = arg; - if (!vfd->vidioc_g_input) + if (!ops->vidioc_g_input) break; - ret = vfd->vidioc_g_input(file, fh, i); + ret = ops->vidioc_g_input(file, fh, i); if (!ret) dbgarg(cmd, "value=%d\n", *i); break; @@ -1190,10 +1200,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { unsigned int *i = arg; - if (!vfd->vidioc_s_input) + if (!ops->vidioc_s_input) break; dbgarg(cmd, "value=%d\n", *i); - ret = vfd->vidioc_s_input(file, fh, *i); + ret = ops->vidioc_s_input(file, fh, *i); break; } @@ -1203,12 +1213,12 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_output *p = arg; int i = p->index; - if (!vfd->vidioc_enum_output) + if (!ops->vidioc_enum_output) break; memset(p, 0, sizeof(*p)); p->index = i; - ret = vfd->vidioc_enum_output(file, fh, p); + ret = ops->vidioc_enum_output(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, type=%d, " "audioset=0x%x, " @@ -1221,9 +1231,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { unsigned int *i = arg; - if (!vfd->vidioc_g_output) + if (!ops->vidioc_g_output) break; - ret = vfd->vidioc_g_output(file, fh, i); + ret = ops->vidioc_g_output(file, fh, i); if (!ret) dbgarg(cmd, "value=%d\n", *i); break; @@ -1232,10 +1242,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { unsigned int *i = arg; - if (!vfd->vidioc_s_output) + if (!ops->vidioc_s_output) break; dbgarg(cmd, "value=%d\n", *i); - ret = vfd->vidioc_s_output(file, fh, *i); + ret = ops->vidioc_s_output(file, fh, *i); break; } @@ -1244,9 +1254,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_queryctrl *p = arg; - if (!vfd->vidioc_queryctrl) + if (!ops->vidioc_queryctrl) break; - ret = vfd->vidioc_queryctrl(file, fh, p); + ret = ops->vidioc_queryctrl(file, fh, p); if (!ret) dbgarg(cmd, "id=0x%x, type=%d, name=%s, min/max=%d/%d, " "step=%d, default=%d, flags=0x%08x\n", @@ -1261,9 +1271,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_control *p = arg; - if (vfd->vidioc_g_ctrl) - ret = vfd->vidioc_g_ctrl(file, fh, p); - else if (vfd->vidioc_g_ext_ctrls) { + if (ops->vidioc_g_ctrl) + ret = ops->vidioc_g_ctrl(file, fh, p); + else if (ops->vidioc_g_ext_ctrls) { struct v4l2_ext_controls ctrls; struct v4l2_ext_control ctrl; @@ -1273,7 +1283,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ctrl.id = p->id; ctrl.value = p->value; if (check_ext_ctrls(&ctrls, 1)) { - ret = vfd->vidioc_g_ext_ctrls(file, fh, &ctrls); + ret = ops->vidioc_g_ext_ctrls(file, fh, &ctrls); if (ret == 0) p->value = ctrl.value; } @@ -1291,16 +1301,16 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_ext_controls ctrls; struct v4l2_ext_control ctrl; - if (!vfd->vidioc_s_ctrl && !vfd->vidioc_s_ext_ctrls) + if (!ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls) break; dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); - if (vfd->vidioc_s_ctrl) { - ret = vfd->vidioc_s_ctrl(file, fh, p); + if (ops->vidioc_s_ctrl) { + ret = ops->vidioc_s_ctrl(file, fh, p); break; } - if (!vfd->vidioc_s_ext_ctrls) + if (!ops->vidioc_s_ext_ctrls) break; ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); @@ -1309,7 +1319,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ctrl.id = p->id; ctrl.value = p->value; if (check_ext_ctrls(&ctrls, 1)) - ret = vfd->vidioc_s_ext_ctrls(file, fh, &ctrls); + ret = ops->vidioc_s_ext_ctrls(file, fh, &ctrls); break; } case VIDIOC_G_EXT_CTRLS: @@ -1317,10 +1327,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_ext_controls *p = arg; p->error_idx = p->count; - if (!vfd->vidioc_g_ext_ctrls) + if (!ops->vidioc_g_ext_ctrls) break; if (check_ext_ctrls(p, 0)) - ret = vfd->vidioc_g_ext_ctrls(file, fh, p); + ret = ops->vidioc_g_ext_ctrls(file, fh, p); v4l_print_ext_ctrls(cmd, vfd, p, !ret); break; } @@ -1329,11 +1339,11 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_ext_controls *p = arg; p->error_idx = p->count; - if (!vfd->vidioc_s_ext_ctrls) + if (!ops->vidioc_s_ext_ctrls) break; v4l_print_ext_ctrls(cmd, vfd, p, 1); if (check_ext_ctrls(p, 0)) - ret = vfd->vidioc_s_ext_ctrls(file, fh, p); + ret = ops->vidioc_s_ext_ctrls(file, fh, p); break; } case VIDIOC_TRY_EXT_CTRLS: @@ -1341,20 +1351,20 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_ext_controls *p = arg; p->error_idx = p->count; - if (!vfd->vidioc_try_ext_ctrls) + if (!ops->vidioc_try_ext_ctrls) break; v4l_print_ext_ctrls(cmd, vfd, p, 1); if (check_ext_ctrls(p, 0)) - ret = vfd->vidioc_try_ext_ctrls(file, fh, p); + ret = ops->vidioc_try_ext_ctrls(file, fh, p); break; } case VIDIOC_QUERYMENU: { struct v4l2_querymenu *p = arg; - if (!vfd->vidioc_querymenu) + if (!ops->vidioc_querymenu) break; - ret = vfd->vidioc_querymenu(file, fh, p); + ret = ops->vidioc_querymenu(file, fh, p); if (!ret) dbgarg(cmd, "id=0x%x, index=%d, name=%s\n", p->id, p->index, p->name); @@ -1368,9 +1378,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_audio *p = arg; - if (!vfd->vidioc_enumaudio) + if (!ops->vidioc_enumaudio) break; - ret = vfd->vidioc_enumaudio(file, fh, p); + ret = ops->vidioc_enumaudio(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " "mode=0x%x\n", p->index, p->name, @@ -1384,12 +1394,12 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_audio *p = arg; __u32 index = p->index; - if (!vfd->vidioc_g_audio) + if (!ops->vidioc_g_audio) break; memset(p, 0, sizeof(*p)); p->index = index; - ret = vfd->vidioc_g_audio(file, fh, p); + ret = ops->vidioc_g_audio(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " "mode=0x%x\n", p->index, @@ -1402,22 +1412,22 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_audio *p = arg; - if (!vfd->vidioc_s_audio) + if (!ops->vidioc_s_audio) break; dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " "mode=0x%x\n", p->index, p->name, p->capability, p->mode); - ret = vfd->vidioc_s_audio(file, fh, p); + ret = ops->vidioc_s_audio(file, fh, p); break; } case VIDIOC_ENUMAUDOUT: { struct v4l2_audioout *p = arg; - if (!vfd->vidioc_enumaudout) + if (!ops->vidioc_enumaudout) break; dbgarg(cmd, "Enum for index=%d\n", p->index); - ret = vfd->vidioc_enumaudout(file, fh, p); + ret = ops->vidioc_enumaudout(file, fh, p); if (!ret) dbgarg2("index=%d, name=%s, capability=%d, " "mode=%d\n", p->index, p->name, @@ -1428,10 +1438,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_audioout *p = arg; - if (!vfd->vidioc_g_audout) + if (!ops->vidioc_g_audout) break; dbgarg(cmd, "Enum for index=%d\n", p->index); - ret = vfd->vidioc_g_audout(file, fh, p); + ret = ops->vidioc_g_audout(file, fh, p); if (!ret) dbgarg2("index=%d, name=%s, capability=%d, " "mode=%d\n", p->index, p->name, @@ -1442,22 +1452,22 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_audioout *p = arg; - if (!vfd->vidioc_s_audout) + if (!ops->vidioc_s_audout) break; dbgarg(cmd, "index=%d, name=%s, capability=%d, " "mode=%d\n", p->index, p->name, p->capability, p->mode); - ret = vfd->vidioc_s_audout(file, fh, p); + ret = ops->vidioc_s_audout(file, fh, p); break; } case VIDIOC_G_MODULATOR: { struct v4l2_modulator *p = arg; - if (!vfd->vidioc_g_modulator) + if (!ops->vidioc_g_modulator) break; - ret = vfd->vidioc_g_modulator(file, fh, p); + ret = ops->vidioc_g_modulator(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, " "capability=%d, rangelow=%d," @@ -1471,23 +1481,23 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_modulator *p = arg; - if (!vfd->vidioc_s_modulator) + if (!ops->vidioc_s_modulator) break; dbgarg(cmd, "index=%d, name=%s, capability=%d, " "rangelow=%d, rangehigh=%d, txsubchans=%d\n", p->index, p->name, p->capability, p->rangelow, p->rangehigh, p->txsubchans); - ret = vfd->vidioc_s_modulator(file, fh, p); + ret = ops->vidioc_s_modulator(file, fh, p); break; } case VIDIOC_G_CROP: { struct v4l2_crop *p = arg; - if (!vfd->vidioc_g_crop) + if (!ops->vidioc_g_crop) break; dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - ret = vfd->vidioc_g_crop(file, fh, p); + ret = ops->vidioc_g_crop(file, fh, p); if (!ret) dbgrect(vfd, "", &p->c); break; @@ -1496,11 +1506,11 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_crop *p = arg; - if (!vfd->vidioc_s_crop) + if (!ops->vidioc_s_crop) break; dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); dbgrect(vfd, "", &p->c); - ret = vfd->vidioc_s_crop(file, fh, p); + ret = ops->vidioc_s_crop(file, fh, p); break; } case VIDIOC_CROPCAP: @@ -1508,10 +1518,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_cropcap *p = arg; /*FIXME: Should also show v4l2_fract pixelaspect */ - if (!vfd->vidioc_cropcap) + if (!ops->vidioc_cropcap) break; dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - ret = vfd->vidioc_cropcap(file, fh, p); + ret = ops->vidioc_cropcap(file, fh, p); if (!ret) { dbgrect(vfd, "bounds ", &p->bounds); dbgrect(vfd, "defrect ", &p->defrect); @@ -1522,9 +1532,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_jpegcompression *p = arg; - if (!vfd->vidioc_g_jpegcomp) + if (!ops->vidioc_g_jpegcomp) break; - ret = vfd->vidioc_g_jpegcomp(file, fh, p); + ret = ops->vidioc_g_jpegcomp(file, fh, p); if (!ret) dbgarg(cmd, "quality=%d, APPn=%d, " "APP_len=%d, COM_len=%d, " @@ -1537,22 +1547,22 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_jpegcompression *p = arg; - if (!vfd->vidioc_g_jpegcomp) + if (!ops->vidioc_g_jpegcomp) break; dbgarg(cmd, "quality=%d, APPn=%d, APP_len=%d, " "COM_len=%d, jpeg_markers=%d\n", p->quality, p->APPn, p->APP_len, p->COM_len, p->jpeg_markers); - ret = vfd->vidioc_s_jpegcomp(file, fh, p); + ret = ops->vidioc_s_jpegcomp(file, fh, p); break; } case VIDIOC_G_ENC_INDEX: { struct v4l2_enc_idx *p = arg; - if (!vfd->vidioc_g_enc_index) + if (!ops->vidioc_g_enc_index) break; - ret = vfd->vidioc_g_enc_index(file, fh, p); + ret = ops->vidioc_g_enc_index(file, fh, p); if (!ret) dbgarg(cmd, "entries=%d, entries_cap=%d\n", p->entries, p->entries_cap); @@ -1562,10 +1572,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_encoder_cmd *p = arg; - if (!vfd->vidioc_encoder_cmd) + if (!ops->vidioc_encoder_cmd) break; memset(&p->raw, 0, sizeof(p->raw)); - ret = vfd->vidioc_encoder_cmd(file, fh, p); + ret = ops->vidioc_encoder_cmd(file, fh, p); if (!ret) dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); break; @@ -1574,10 +1584,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_encoder_cmd *p = arg; - if (!vfd->vidioc_try_encoder_cmd) + if (!ops->vidioc_try_encoder_cmd) break; memset(&p->raw, 0, sizeof(p->raw)); - ret = vfd->vidioc_try_encoder_cmd(file, fh, p); + ret = ops->vidioc_try_encoder_cmd(file, fh, p); if (!ret) dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); break; @@ -1590,8 +1600,8 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, memset(p, 0, sizeof(*p)); p->type = type; - if (vfd->vidioc_g_parm) { - ret = vfd->vidioc_g_parm(file, fh, p); + if (ops->vidioc_g_parm) { + ret = ops->vidioc_g_parm(file, fh, p); } else { struct v4l2_standard s; @@ -1612,10 +1622,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_streamparm *p = arg; - if (!vfd->vidioc_s_parm) + if (!ops->vidioc_s_parm) break; dbgarg(cmd, "type=%d\n", p->type); - ret = vfd->vidioc_s_parm(file, fh, p); + ret = ops->vidioc_s_parm(file, fh, p); break; } case VIDIOC_G_TUNER: @@ -1623,13 +1633,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_tuner *p = arg; __u32 index = p->index; - if (!vfd->vidioc_g_tuner) + if (!ops->vidioc_g_tuner) break; memset(p, 0, sizeof(*p)); p->index = index; - ret = vfd->vidioc_g_tuner(file, fh, p); + ret = ops->vidioc_g_tuner(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, type=%d, " "capability=0x%x, rangelow=%d, " @@ -1645,7 +1655,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_tuner *p = arg; - if (!vfd->vidioc_s_tuner) + if (!ops->vidioc_s_tuner) break; dbgarg(cmd, "index=%d, name=%s, type=%d, " "capability=0x%x, rangelow=%d, " @@ -1655,19 +1665,19 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, p->capability, p->rangelow, p->rangehigh, p->signal, p->afc, p->rxsubchans, p->audmode); - ret = vfd->vidioc_s_tuner(file, fh, p); + ret = ops->vidioc_s_tuner(file, fh, p); break; } case VIDIOC_G_FREQUENCY: { struct v4l2_frequency *p = arg; - if (!vfd->vidioc_g_frequency) + if (!ops->vidioc_g_frequency) break; memset(p->reserved, 0, sizeof(p->reserved)); - ret = vfd->vidioc_g_frequency(file, fh, p); + ret = ops->vidioc_g_frequency(file, fh, p); if (!ret) dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", p->tuner, p->type, p->frequency); @@ -1677,11 +1687,11 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_frequency *p = arg; - if (!vfd->vidioc_s_frequency) + if (!ops->vidioc_s_frequency) break; dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", p->tuner, p->type, p->frequency); - ret = vfd->vidioc_s_frequency(file, fh, p); + ret = ops->vidioc_s_frequency(file, fh, p); break; } case VIDIOC_G_SLICED_VBI_CAP: @@ -1689,21 +1699,21 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_sliced_vbi_cap *p = arg; __u32 type = p->type; - if (!vfd->vidioc_g_sliced_vbi_cap) + if (!ops->vidioc_g_sliced_vbi_cap) break; memset(p, 0, sizeof(*p)); p->type = type; dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - ret = vfd->vidioc_g_sliced_vbi_cap(file, fh, p); + ret = ops->vidioc_g_sliced_vbi_cap(file, fh, p); if (!ret) dbgarg2("service_set=%d\n", p->service_set); break; } case VIDIOC_LOG_STATUS: { - if (!vfd->vidioc_log_status) + if (!ops->vidioc_log_status) break; - ret = vfd->vidioc_log_status(file, fh); + ret = ops->vidioc_log_status(file, fh); break; } #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -1713,8 +1723,8 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, if (!capable(CAP_SYS_ADMIN)) ret = -EPERM; - else if (vfd->vidioc_g_register) - ret = vfd->vidioc_g_register(file, fh, p); + else if (ops->vidioc_g_register) + ret = ops->vidioc_g_register(file, fh, p); break; } case VIDIOC_DBG_S_REGISTER: @@ -1723,8 +1733,8 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, if (!capable(CAP_SYS_ADMIN)) ret = -EPERM; - else if (vfd->vidioc_s_register) - ret = vfd->vidioc_s_register(file, fh, p); + else if (ops->vidioc_s_register) + ret = ops->vidioc_s_register(file, fh, p); break; } #endif @@ -1732,30 +1742,30 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_chip_ident *p = arg; - if (!vfd->vidioc_g_chip_ident) + if (!ops->vidioc_g_chip_ident) break; - ret = vfd->vidioc_g_chip_ident(file, fh, p); + ret = ops->vidioc_g_chip_ident(file, fh, p); if (!ret) dbgarg(cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision); break; } - default: - { - if (!vfd->vidioc_default) - break; - ret = vfd->vidioc_default(file, fh, cmd, arg); - break; - } case VIDIOC_S_HW_FREQ_SEEK: { struct v4l2_hw_freq_seek *p = arg; - if (!vfd->vidioc_s_hw_freq_seek) + if (!ops->vidioc_s_hw_freq_seek) break; dbgarg(cmd, "tuner=%d, type=%d, seek_upward=%d, wrap_around=%d\n", p->tuner, p->type, p->seek_upward, p->wrap_around); - ret = vfd->vidioc_s_hw_freq_seek(file, fh, p); + ret = ops->vidioc_s_hw_freq_seek(file, fh, p); + break; + } + default: + { + if (!ops->vidioc_default) + break; + ret = ops->vidioc_default(file, fh, cmd, arg); break; } } /* switch */ diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index e4b3a006c71..639210e5264 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1066,13 +1066,7 @@ static const struct file_operations vivi_fops = { .llseek = no_llseek, }; -static struct video_device vivi_template = { - .name = "vivi", - .type = VID_TYPE_CAPTURE, - .fops = &vivi_fops, - .minor = -1, - .release = video_device_release, - +static const struct v4l2_ioctl_ops vivi_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1094,6 +1088,16 @@ static struct video_device vivi_template = { #ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf, #endif +}; + +static struct video_device vivi_template = { + .name = "vivi", + .type = VID_TYPE_CAPTURE, + .fops = &vivi_fops, + .ioctl_ops = &vivi_ioctl_ops, + .minor = -1, + .release = video_device_release, + .tvnorms = V4L2_STD_525_60, .current_norm = V4L2_STD_NTSC_M, }; diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c index ea5265c2298..617ed2856b2 100644 --- a/drivers/media/video/zr364xx.c +++ b/drivers/media/video/zr364xx.c @@ -762,14 +762,7 @@ static const struct file_operations zr364xx_fops = { .llseek = no_llseek, }; -static struct video_device zr364xx_template = { - .owner = THIS_MODULE, - .name = DRIVER_DESC, - .type = VID_TYPE_CAPTURE, - .fops = &zr364xx_fops, - .release = video_device_release, - .minor = -1, - +static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = { .vidioc_querycap = zr364xx_vidioc_querycap, .vidioc_enum_fmt_vid_cap = zr364xx_vidioc_enum_fmt_vid_cap, .vidioc_try_fmt_vid_cap = zr364xx_vidioc_try_fmt_vid_cap, @@ -785,6 +778,16 @@ static struct video_device zr364xx_template = { .vidioc_s_ctrl = zr364xx_vidioc_s_ctrl, }; +static struct video_device zr364xx_template = { + .owner = THIS_MODULE, + .name = DRIVER_DESC, + .type = VID_TYPE_CAPTURE, + .fops = &zr364xx_fops, + .ioctl_ops = &zr364xx_ioctl_ops, + .release = video_device_release, + .minor = -1, +}; + /*******************/ -- cgit v1.2.3 From 9c39d7eafa366b807067697f7fc5b14d8b865179 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 Jul 2008 07:51:45 -0300 Subject: V4L/DVB (8483): Remove obsolete owner field from video_device struct. According to an old comment this should have been removed in 2.6.15. Better late than never... Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/dsbr100.c | 1 - drivers/media/radio/miropcm20-radio.c | 1 - drivers/media/radio/radio-aimslab.c | 1 - drivers/media/radio/radio-aztech.c | 1 - drivers/media/radio/radio-cadet.c | 1 - drivers/media/radio/radio-gemtek-pci.c | 1 - drivers/media/radio/radio-gemtek.c | 1 - drivers/media/radio/radio-maxiradio.c | 1 - drivers/media/radio/radio-rtrack2.c | 1 - drivers/media/radio/radio-sf16fmi.c | 1 - drivers/media/radio/radio-sf16fmr2.c | 1 - drivers/media/radio/radio-si470x.c | 1 - drivers/media/radio/radio-terratec.c | 1 - drivers/media/radio/radio-trust.c | 1 - drivers/media/radio/radio-typhoon.c | 1 - drivers/media/radio/radio-zoltrix.c | 1 - drivers/media/video/bw-qcam.c | 1 - drivers/media/video/c-qcam.c | 1 - drivers/media/video/cpia.c | 1 - drivers/media/video/cpia2/cpia2_v4l.c | 1 - drivers/media/video/et61x251/et61x251_core.c | 1 - drivers/media/video/meye.c | 1 - drivers/media/video/ov511.c | 1 - drivers/media/video/pms.c | 1 - drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 1 - drivers/media/video/pwc/pwc-if.c | 2 -- drivers/media/video/saa5246a.c | 1 - drivers/media/video/saa5249.c | 1 - drivers/media/video/se401.c | 1 - drivers/media/video/sn9c102/sn9c102_core.c | 1 - drivers/media/video/stv680.c | 1 - drivers/media/video/usbvideo/usbvideo.c | 1 - drivers/media/video/usbvideo/vicam.c | 1 - drivers/media/video/usbvision/usbvision-video.c | 3 --- drivers/media/video/w9966.c | 1 - drivers/media/video/w9968cf.c | 1 - drivers/media/video/zc0301/zc0301_core.c | 1 - drivers/media/video/zr364xx.c | 1 - 38 files changed, 41 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index 08bf5e8031d..0edada6f4b3 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -462,7 +462,6 @@ static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = { /* V4L2 interface */ static struct video_device dsbr100_videodev_template = { - .owner = THIS_MODULE, .name = "D-Link DSB-R 100", .type = VID_TYPE_TUNER, .fops = &usb_dsbr100_fops, diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c index 4a332fe8b64..594e246dfcf 100644 --- a/drivers/media/radio/miropcm20-radio.c +++ b/drivers/media/radio/miropcm20-radio.c @@ -229,7 +229,6 @@ static const struct file_operations pcm20_fops = { }; static struct video_device pcm20_radio = { - .owner = THIS_MODULE, .name = "Miro PCM 20 radio", .type = VID_TYPE_TUNER, .fops = &pcm20_fops, diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index be9bd7adaf6..2540df6dc2c 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -405,7 +405,6 @@ static const struct v4l2_ioctl_ops rtrack_ioctl_ops = { }; static struct video_device rtrack_radio = { - .owner = THIS_MODULE, .name = "RadioTrack radio", .type = VID_TYPE_TUNER, .fops = &rtrack_fops, diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c index 04c738b62d0..537f2f47950 100644 --- a/drivers/media/radio/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c @@ -369,7 +369,6 @@ static const struct v4l2_ioctl_ops aztech_ioctl_ops = { }; static struct video_device aztech_radio = { - .owner = THIS_MODULE, .name = "Aztech radio", .type = VID_TYPE_TUNER, .fops = &aztech_fops, diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 36b850fc14b..362a279f068 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -586,7 +586,6 @@ static const struct v4l2_ioctl_ops cadet_ioctl_ops = { }; static struct video_device cadet_radio = { - .owner = THIS_MODULE, .name = "Cadet radio", .type = VID_TYPE_TUNER, .fops = &cadet_fops, diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c index c41b35f3b12..b8c515762b4 100644 --- a/drivers/media/radio/radio-gemtek-pci.c +++ b/drivers/media/radio/radio-gemtek-pci.c @@ -391,7 +391,6 @@ static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = { }; static struct video_device vdev_template = { - .owner = THIS_MODULE, .name = "Gemtek PCI Radio", .type = VID_TYPE_TUNER, .fops = &gemtek_pci_fops, diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index f82b59f35e3..45b47c1643e 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -569,7 +569,6 @@ static const struct v4l2_ioctl_ops gemtek_ioctl_ops = { }; static struct video_device gemtek_radio = { - .owner = THIS_MODULE, .name = "GemTek Radio card", .type = VID_TYPE_TUNER, .fops = &gemtek_fops, diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index 780516daebb..1b909960649 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -390,7 +390,6 @@ static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = { }; static struct video_device maxiradio_radio = { - .owner = THIS_MODULE, .name = "Maxi Radio FM2000 radio", .type = VID_TYPE_TUNER, .fops = &maxiradio_fops, diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index 045ae9d1067..e065cb16dc5 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c @@ -311,7 +311,6 @@ static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = { }; static struct video_device rtrack2_radio = { - .owner = THIS_MODULE, .name = "RadioTrack II radio", .type = VID_TYPE_TUNER, .fops = &rtrack2_fops, diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 75b68a02454..975f8521848 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -311,7 +311,6 @@ static const struct v4l2_ioctl_ops fmi_ioctl_ops = { }; static struct video_device fmi_radio = { - .owner = THIS_MODULE, .name = "SF16FMx radio", .type = VID_TYPE_TUNER, .fops = &fmi_fops, diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index 5ffddce8001..2786722b494 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -427,7 +427,6 @@ static const struct v4l2_ioctl_ops fmr2_ioctl_ops = { }; static struct video_device fmr2_radio = { - .owner = THIS_MODULE, .name = "SF16FMR2 radio", .type = VID_TYPE_TUNER, .fops = &fmr2_fops, diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index b829c67ecf0..3cf78ccdc58 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c @@ -1611,7 +1611,6 @@ static struct video_device si470x_viddev_template = { .name = DRIVER_NAME, .type = VID_TYPE_TUNER, .release = video_device_release, - .owner = THIS_MODULE, }; diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index 3a67471f999..b3f669d0691 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -383,7 +383,6 @@ static const struct v4l2_ioctl_ops terratec_ioctl_ops = { }; static struct video_device terratec_radio = { - .owner = THIS_MODULE, .name = "TerraTec ActiveRadio", .type = VID_TYPE_TUNER, .fops = &terratec_fops, diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index e3340018091..74aefda868e 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c @@ -363,7 +363,6 @@ static const struct v4l2_ioctl_ops trust_ioctl_ops = { }; static struct video_device trust_radio = { - .owner = THIS_MODULE, .name = "Trust FM Radio", .type = VID_TYPE_TUNER, .fops = &trust_fops, diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c index 48b5d2bc627..6eb39b7ab75 100644 --- a/drivers/media/radio/radio-typhoon.c +++ b/drivers/media/radio/radio-typhoon.c @@ -361,7 +361,6 @@ static const struct v4l2_ioctl_ops typhoon_ioctl_ops = { }; static struct video_device typhoon_radio = { - .owner = THIS_MODULE, .name = "Typhoon Radio", .type = VID_TYPE_TUNER, .fops = &typhoon_fops, diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index c60344326cd..4afcb09a4af 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c @@ -424,7 +424,6 @@ static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = { }; static struct video_device zoltrix_radio = { - .owner = THIS_MODULE, .name = "Zoltrix Radio Plus", .type = VID_TYPE_TUNER, .fops = &zoltrix_fops, diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index e367862313e..ec870c781c0 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -907,7 +907,6 @@ static const struct file_operations qcam_fops = { }; static struct video_device qcam_template= { - .owner = THIS_MODULE, .name = "Connectix Quickcam", .type = VID_TYPE_CAPTURE, .fops = &qcam_fops, diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c index 8d690410c84..62ed8949d46 100644 --- a/drivers/media/video/c-qcam.c +++ b/drivers/media/video/c-qcam.c @@ -702,7 +702,6 @@ static const struct file_operations qcam_fops = { static struct video_device qcam_template= { - .owner = THIS_MODULE, .name = "Colour QuickCam", .type = VID_TYPE_CAPTURE, .fops = &qcam_fops, diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c index 2a81376ef50..5d2ef48137c 100644 --- a/drivers/media/video/cpia.c +++ b/drivers/media/video/cpia.c @@ -3799,7 +3799,6 @@ static const struct file_operations cpia_fops = { }; static struct video_device cpia_template = { - .owner = THIS_MODULE, .name = "CPiA Camera", .type = VID_TYPE_CAPTURE, .fops = &cpia_fops, diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 8817c384146..4e45de78df5 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -1936,7 +1936,6 @@ static const struct file_operations fops_template = { static struct video_device cpia2_template = { /* I could not find any place for the old .initialize initializer?? */ - .owner= THIS_MODULE, .name= "CPiA2 Camera", .type= VID_TYPE_CAPTURE, .type2 = V4L2_CAP_VIDEO_CAPTURE | diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 8cd5f37425e..3e71ea7bbe2 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -2585,7 +2585,6 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) } strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera"); - cam->v4ldev->owner = THIS_MODULE; cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; cam->v4ldev->fops = &et61x251_fops; cam->v4ldev->minor = video_nr[dev_nr]; diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index fd16ef0a586..f9a6e1e8b4b 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -1720,7 +1720,6 @@ static const struct v4l2_ioctl_ops meye_ioctl_ops = { }; static struct video_device meye_template = { - .owner = THIS_MODULE, .name = "meye", .type = VID_TYPE_CAPTURE, .fops = &meye_fops, diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index b72e5660bc1..f732b035570 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c @@ -4666,7 +4666,6 @@ static const struct file_operations ov511_fops = { }; static struct video_device vdev_template = { - .owner = THIS_MODULE, .name = "OV511 USB Camera", .type = VID_TYPE_CAPTURE, .fops = &ov511_fops, diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c index 260c1d3f969..8c72e4df85a 100644 --- a/drivers/media/video/pms.c +++ b/drivers/media/video/pms.c @@ -895,7 +895,6 @@ static const struct file_operations pms_fops = { static struct video_device pms_template= { - .owner = THIS_MODULE, .name = "Mediavision PMS", .type = VID_TYPE_CAPTURE, .fops = &pms_fops, diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index bd6169fbdcc..ceb549ac752 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -1161,7 +1161,6 @@ static const struct file_operations vdev_fops = { static struct video_device vdev_template = { - .owner = THIS_MODULE, .type = VID_TYPE_CAPTURE | VID_TYPE_TUNER, .type2 = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_TUNER | V4L2_CAP_AUDIO diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index b4de82115e5..4625b265bf9 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -165,7 +165,6 @@ static const struct file_operations pwc_fops = { .llseek = no_llseek, }; static struct video_device pwc_template = { - .owner = THIS_MODULE, .name = "Philips Webcam", /* Filled in later */ .type = VID_TYPE_CAPTURE, .release = video_device_release, @@ -1769,7 +1768,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); pdev->vdev->parent = &(udev->dev); strcpy(pdev->vdev->name, name); - pdev->vdev->owner = THIS_MODULE; video_set_drvdata(pdev->vdev, pdev); pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c index 8d69632a665..e6a3fa48298 100644 --- a/drivers/media/video/saa5246a.c +++ b/drivers/media/video/saa5246a.c @@ -830,7 +830,6 @@ static const struct file_operations saa_fops = { static struct video_device saa_template = { - .owner = THIS_MODULE, .name = IF_NAME, .type = VID_TYPE_TELETEXT, .fops = &saa_fops, diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c index 812cfe3fd3f..6f14619bda4 100644 --- a/drivers/media/video/saa5249.c +++ b/drivers/media/video/saa5249.c @@ -711,7 +711,6 @@ static const struct file_operations saa_fops = { static struct video_device saa_template = { - .owner = THIS_MODULE, .name = IF_NAME, .type = VID_TYPE_TELETEXT, /*| VID_TYPE_TUNER ?? */ .fops = &saa_fops, diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c index 1cd629380f7..b4dd60b0f8f 100644 --- a/drivers/media/video/se401.c +++ b/drivers/media/video/se401.c @@ -1230,7 +1230,6 @@ static const struct file_operations se401_fops = { .llseek = no_llseek, }; static struct video_device se401_template = { - .owner = THIS_MODULE, .name = "se401 USB camera", .type = VID_TYPE_CAPTURE, .fops = &se401_fops, diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 475b7819115..c68bf0921e9 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -3309,7 +3309,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) } strcpy(cam->v4ldev->name, "SN9C1xx PC Camera"); - cam->v4ldev->owner = THIS_MODULE; cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; cam->v4ldev->fops = &sn9c102_fops; cam->v4ldev->minor = video_nr[dev_nr]; diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index da94d3fd8fa..fdcb58b0c12 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -1401,7 +1401,6 @@ static const struct file_operations stv680_fops = { .llseek = no_llseek, }; static struct video_device stv680_template = { - .owner = THIS_MODULE, .name = "STV0680 USB camera", .type = VID_TYPE_CAPTURE, .fops = &stv680_fops, diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c index 7e6ab2910c1..357cee40fb3 100644 --- a/drivers/media/video/usbvideo/usbvideo.c +++ b/drivers/media/video/usbvideo/usbvideo.c @@ -952,7 +952,6 @@ static const struct file_operations usbvideo_fops = { .llseek = no_llseek, }; static const struct video_device usbvideo_template = { - .owner = THIS_MODULE, .type = VID_TYPE_CAPTURE, .fops = &usbvideo_fops, }; diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c index 40d053e0d5b..e2dec6fb0da 100644 --- a/drivers/media/video/usbvideo/vicam.c +++ b/drivers/media/video/usbvideo/vicam.c @@ -791,7 +791,6 @@ static const struct file_operations vicam_fops = { }; static struct video_device vicam_template = { - .owner = THIS_MODULE, .name = "ViCam-based USB Camera", .type = VID_TYPE_CAPTURE, .fops = &vicam_fops, diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 7eccdc1ea2d..e97f955aad6 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -1406,7 +1406,6 @@ static const struct v4l2_ioctl_ops usbvision_ioctl_ops = { }; static struct video_device usbvision_video_template = { - .owner = THIS_MODULE, .type = VID_TYPE_TUNER | VID_TYPE_CAPTURE, .fops = &usbvision_fops, .ioctl_ops = &usbvision_ioctl_ops, @@ -1445,7 +1444,6 @@ static const struct v4l2_ioctl_ops usbvision_radio_ioctl_ops = { }; static struct video_device usbvision_radio_template = { - .owner = THIS_MODULE, .type = VID_TYPE_TUNER, .fops = &usbvision_radio_fops, .name = "usbvision-radio", @@ -1469,7 +1467,6 @@ static const struct file_operations usbvision_vbi_fops = { static struct video_device usbvision_vbi_template= { - .owner = THIS_MODULE, .type = VID_TYPE_TUNER, .fops = &usbvision_vbi_fops, .release = video_device_release, diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c index a63e11f8399..1641998c73e 100644 --- a/drivers/media/video/w9966.c +++ b/drivers/media/video/w9966.c @@ -196,7 +196,6 @@ static const struct file_operations w9966_fops = { .llseek = no_llseek, }; static struct video_device w9966_template = { - .owner = THIS_MODULE, .name = W9966_DRIVERNAME, .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES, .fops = &w9966_fops, diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 56bbeec542c..8f665953c80 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -3550,7 +3550,6 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) } strcpy(cam->v4ldev->name, symbolic(camlist, mod_id)); - cam->v4ldev->owner = THIS_MODULE; cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; cam->v4ldev->fops = &w9968cf_fops; cam->v4ldev->minor = video_nr[dev_nr]; diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c index e5c4e9f5193..0978a7e946b 100644 --- a/drivers/media/video/zc0301/zc0301_core.c +++ b/drivers/media/video/zc0301/zc0301_core.c @@ -1985,7 +1985,6 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) } strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera"); - cam->v4ldev->owner = THIS_MODULE; cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; cam->v4ldev->fops = &zc0301_fops; cam->v4ldev->minor = video_nr[dev_nr]; diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c index 617ed2856b2..36ba36a5e2e 100644 --- a/drivers/media/video/zr364xx.c +++ b/drivers/media/video/zr364xx.c @@ -779,7 +779,6 @@ static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = { }; static struct video_device zr364xx_template = { - .owner = THIS_MODULE, .name = DRIVER_DESC, .type = VID_TYPE_CAPTURE, .fops = &zr364xx_fops, -- cgit v1.2.3 From 322e4095c9261d4cf0326f10d8e398d05e66521c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 22 Jul 2008 16:25:35 -0300 Subject: V4L/DVB (8484): videodev: missed two more usages of the removed 'owner' field. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/arv.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index 8c7d1958856..56ebfd5ef6f 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c @@ -754,7 +754,6 @@ static const struct file_operations ar_fops = { }; static struct video_device ar_template = { - .owner = THIS_MODULE, .name = "Colour AR VGA", .type = VID_TYPE_CAPTURE, .fops = &ar_fops, -- cgit v1.2.3 From 58cfdf9acffb0c61feb0e2bceacd557a2e0b0328 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 25 Jul 2008 04:26:31 -0300 Subject: V4L/DVB (8485): v4l-dvb: remove broken PlanB driver The PlanB driver has been broken since around May 2004. No one stepped in to maintain it, so it is now being removed. Signed-off-by: Adrian Bunk Acked-by: Michel Lanners Acked-by: Benjamin Herrenschmidt Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 11 - drivers/media/video/Makefile | 1 - drivers/media/video/planb.c | 2309 ----------------------------------------- drivers/media/video/planb.h | 232 ----- drivers/media/video/saa7196.h | 117 --- 5 files changed, 2670 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 2a747db6dc3..d4a6e56a713 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -487,17 +487,6 @@ config VIDEO_PMS To compile this driver as a module, choose M here: the module will be called pms. -config VIDEO_PLANB - tristate "PlanB Video-In on PowerMac" - depends on PPC_PMAC && VIDEO_V4L1 && BROKEN - help - PlanB is the V4L driver for the PowerMac 7x00/8x00 series video - input hardware. If you want to experiment with this, say Y. - Otherwise, or if you don't understand a word, say N. See - for more info. - - Saying M will compile this driver as a module (planb). - config VIDEO_BWQCAM tristate "Quickcam BW Video For Linux" depends on PARPORT && VIDEO_V4L1 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 9de1e488524..bbc6f8b8229 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -57,7 +57,6 @@ obj-$(CONFIG_VIDEO_ZORAN_DC30) += zr36050.o zr36016.o obj-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o obj-$(CONFIG_VIDEO_PMS) += pms.o -obj-$(CONFIG_VIDEO_PLANB) += planb.o obj-$(CONFIG_VIDEO_VINO) += vino.o indycam.o obj-$(CONFIG_VIDEO_STRADIS) += stradis.o obj-$(CONFIG_VIDEO_CPIA) += cpia.o diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c index 36047d4e70f..e69de29bb2d 100644 --- a/drivers/media/video/planb.c +++ b/drivers/media/video/planb.c @@ -1,2309 +0,0 @@ -/* - planb - PlanB frame grabber driver - - PlanB is used in the 7x00/8x00 series of PowerMacintosh - Computers as video input DMA controller. - - Copyright (C) 1998 Michel Lanners (mlan@cpu.lu) - - Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de) - - Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* $Id: planb.c,v 1.18 1999/05/02 17:36:34 mlan Exp $ */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "planb.h" -#include "saa7196.h" - -/* Would you mind for some ugly debugging? */ -#if 0 -#define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */ -#else -#define DEBUG(x...) /* Don't debug driver */ -#endif - -#if 0 -#define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */ -#else -#define IDEBUG(x...) /* Don't debug interrupt part */ -#endif - -/* Ever seen a Mac with more than 1 of these? */ -#define PLANB_MAX 1 - -static int planb_num; -static struct planb planbs[PLANB_MAX]; -static volatile struct planb_registers *planb_regs; - -static int def_norm = PLANB_DEF_NORM; /* default norm */ -static int video_nr = -1; - -module_param(def_norm, int, 0); -MODULE_PARM_DESC(def_norm, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)"); -module_param(video_nr, int, 0); -MODULE_LICENSE("GPL"); - - -/* ------------------ PlanB Exported Functions ------------------ */ -static long planb_write(struct video_device *, const char *, unsigned long, int); -static long planb_read(struct video_device *, char *, unsigned long, int); -static int planb_open(struct video_device *, int); -static void planb_close(struct video_device *); -static int planb_ioctl(struct video_device *, unsigned int, void *); -static int planb_init_done(struct video_device *); -static int planb_mmap(struct video_device *, const char *, unsigned long); -static void release_planb(void); -int init_planbs(struct video_init *); - -/* ------------------ PlanB Internal Functions ------------------ */ -static int planb_prepare_open(struct planb *); -static void planb_prepare_close(struct planb *); -static void saa_write_reg(unsigned char, unsigned char); -static unsigned char saa_status(int, struct planb *); -static void saa_set(unsigned char, unsigned char, struct planb *); -static void saa_init_regs(struct planb *); -static int grabbuf_alloc(struct planb *); -static int vgrab(struct planb *, struct video_mmap *); -static void add_clip(struct planb *, struct video_clip *); -static void fill_cmd_buff(struct planb *); -static void cmd_buff(struct planb *); -static volatile struct dbdma_cmd *setup_grab_cmd(int, struct planb *); -static void overlay_start(struct planb *); -static void overlay_stop(struct planb *); -static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *, unsigned short, - unsigned int); -static inline void tab_cmd_store(volatile struct dbdma_cmd *, unsigned int, - unsigned int); -static inline void tab_cmd_gen(volatile struct dbdma_cmd *, unsigned short, - unsigned short, unsigned int, unsigned int); -static int init_planb(struct planb *); -static int find_planb(void); -static void planb_pre_capture(int, int, struct planb *); -static volatile struct dbdma_cmd *cmd_geo_setup(volatile struct dbdma_cmd *, - int, int, int, int, int, struct planb *); -static inline void planb_dbdma_stop(volatile struct dbdma_regs *); -static unsigned int saa_geo_setup(int, int, int, int, struct planb *); -static inline int overlay_is_active(struct planb *); - -/*******************************/ -/* Memory management functions */ -/*******************************/ - -static int grabbuf_alloc(struct planb *pb) -{ - int i, npage; - - npage = MAX_GBUFFERS * ((PLANB_MAX_FBUF / PAGE_SIZE + 1) -#ifndef PLANB_GSCANLINE - + MAX_LNUM -#endif /* PLANB_GSCANLINE */ - ); - if ((pb->rawbuf = kmalloc(npage - * sizeof(unsigned long), GFP_KERNEL)) == 0) - return -ENOMEM; - for (i = 0; i < npage; i++) { - pb->rawbuf[i] = (unsigned char *)__get_free_pages(GFP_KERNEL - |GFP_DMA, 0); - if (!pb->rawbuf[i]) - break; - SetPageReserved(virt_to_page(pb->rawbuf[i])); - } - if (i-- < npage) { - printk(KERN_DEBUG "PlanB: init_grab: grab buffer not allocated\n"); - for (; i > 0; i--) { - ClearPageReserved(virt_to_page(pb->rawbuf[i])); - free_pages((unsigned long)pb->rawbuf[i], 0); - } - kfree(pb->rawbuf); - return -ENOBUFS; - } - pb->rawbuf_size = npage; - return 0; -} - -/*****************************/ -/* Hardware access functions */ -/*****************************/ - -static void saa_write_reg(unsigned char addr, unsigned char val) -{ - planb_regs->saa_addr = addr; eieio(); - planb_regs->saa_regval = val; eieio(); - return; -} - -/* return status byte 0 or 1: */ -static unsigned char saa_status(int byte, struct planb *pb) -{ - saa_regs[pb->win.norm][SAA7196_STDC] = - (saa_regs[pb->win.norm][SAA7196_STDC] & ~2) | ((byte & 1) << 1); - saa_write_reg (SAA7196_STDC, saa_regs[pb->win.norm][SAA7196_STDC]); - - /* Let's wait 30msec for this one */ - msleep_interruptible(30); - - return (unsigned char)in_8 (&planb_regs->saa_status); -} - -static void saa_set(unsigned char addr, unsigned char val, struct planb *pb) -{ - if(saa_regs[pb->win.norm][addr] != val) { - saa_regs[pb->win.norm][addr] = val; - saa_write_reg (addr, val); - } - return; -} - -static void saa_init_regs(struct planb *pb) -{ - int i; - - for (i = 0; i < SAA7196_NUMREGS; i++) - saa_write_reg (i, saa_regs[pb->win.norm][i]); -} - -static unsigned int saa_geo_setup(int width, int height, int interlace, int bpp, - struct planb *pb) -{ - int ht, norm = pb->win.norm; - - switch(bpp) { - case 2: - /* RGB555+a 1x16-bit + 16-bit transparent */ - saa_regs[norm][SAA7196_FMTS] &= ~0x3; - break; - case 1: - case 4: - /* RGB888 1x24-bit + 8-bit transparent */ - saa_regs[norm][SAA7196_FMTS] &= ~0x1; - saa_regs[norm][SAA7196_FMTS] |= 0x2; - break; - default: - return -EINVAL; - } - ht = (interlace ? height / 2 : height); - saa_regs[norm][SAA7196_OUTPIX] = (unsigned char) (width & 0x00ff); - saa_regs[norm][SAA7196_HFILT] = (saa_regs[norm][SAA7196_HFILT] & ~0x3) - | (width >> 8 & 0x3); - saa_regs[norm][SAA7196_OUTLINE] = (unsigned char) (ht & 0xff); - saa_regs[norm][SAA7196_VYP] = (saa_regs[norm][SAA7196_VYP] & ~0x3) - | (ht >> 8 & 0x3); - /* feed both fields if interlaced, or else feed only even fields */ - saa_regs[norm][SAA7196_FMTS] = (interlace) ? - (saa_regs[norm][SAA7196_FMTS] & ~0x60) - : (saa_regs[norm][SAA7196_FMTS] | 0x60); - /* transparent mode; extended format enabled */ - saa_regs[norm][SAA7196_DPATH] |= 0x3; - - return 0; -} - -/***************************/ -/* DBDMA support functions */ -/***************************/ - -static inline void planb_dbdma_restart(volatile struct dbdma_regs *ch) -{ - out_le32(&ch->control, PLANB_CLR(RUN)); - out_le32(&ch->control, PLANB_SET(RUN|WAKE) | PLANB_CLR(PAUSE)); -} - -static inline void planb_dbdma_stop(volatile struct dbdma_regs *ch) -{ - int i = 0; - - out_le32(&ch->control, PLANB_CLR(RUN) | PLANB_SET(FLUSH)); - while((in_le32(&ch->status) == (ACTIVE | FLUSH)) && (i < 999)) { - IDEBUG("PlanB: waiting for DMA to stop\n"); - i++; - } -} - -static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *ch, - unsigned short command, unsigned int cmd_dep) -{ - st_le16(&ch->command, command); - st_le32(&ch->cmd_dep, cmd_dep); -} - -static inline void tab_cmd_store(volatile struct dbdma_cmd *ch, - unsigned int phy_addr, unsigned int cmd_dep) -{ - st_le16(&ch->command, STORE_WORD | KEY_SYSTEM); - st_le16(&ch->req_count, 4); - st_le32(&ch->phy_addr, phy_addr); - st_le32(&ch->cmd_dep, cmd_dep); -} - -static inline void tab_cmd_gen(volatile struct dbdma_cmd *ch, - unsigned short command, unsigned short req_count, - unsigned int phy_addr, unsigned int cmd_dep) -{ - st_le16(&ch->command, command); - st_le16(&ch->req_count, req_count); - st_le32(&ch->phy_addr, phy_addr); - st_le32(&ch->cmd_dep, cmd_dep); -} - -static volatile struct dbdma_cmd *cmd_geo_setup( - volatile struct dbdma_cmd *c1, int width, int height, int interlace, - int bpp, int clip, struct planb *pb) -{ - int norm = pb->win.norm; - - if((saa_geo_setup(width, height, interlace, bpp, pb)) != 0) - return (volatile struct dbdma_cmd *)NULL; - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_FMTS); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_FMTS]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_DPATH); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_DPATH]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->even), - bpp | ((clip)? PLANB_CLIPMASK: 0)); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->odd), - bpp | ((clip)? PLANB_CLIPMASK: 0)); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_OUTPIX); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_OUTPIX]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_HFILT); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_HFILT]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_OUTLINE); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_OUTLINE]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_VYP); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_VYP]); - return c1; -} - -/******************************/ -/* misc. supporting functions */ -/******************************/ - -static inline void planb_lock(struct planb *pb) -{ - mutex_lock(&pb->lock); -} - -static inline void planb_unlock(struct planb *pb) -{ - mutex_unlock(&pb->lock); -} - -/***************/ -/* Driver Core */ -/***************/ - -static int planb_prepare_open(struct planb *pb) -{ - int i, size; - - /* allocate memory for two plus alpha command buffers (size: max lines, - plus 40 commands handling, plus 1 alignment), plus dummy command buf, - plus clipmask buffer, plus frame grabbing status */ - size = (pb->tab_size*(2+MAX_GBUFFERS*TAB_FACTOR)+1+MAX_GBUFFERS - * PLANB_DUMMY)*sizeof(struct dbdma_cmd) - +(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8 - +MAX_GBUFFERS*sizeof(unsigned int); - if ((pb->priv_space = kzalloc (size, GFP_KERNEL)) == 0) - return -ENOMEM; - pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *) - DBDMA_ALIGN (pb->priv_space); - pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size; - pb->ch1_cmd_phys = virt_to_bus(pb->ch1_cmd); - pb->cap_cmd[0] = pb->ch2_cmd + pb->tab_size; - pb->pre_cmd[0] = pb->cap_cmd[0] + pb->tab_size * TAB_FACTOR; - for (i = 1; i < MAX_GBUFFERS; i++) { - pb->cap_cmd[i] = pb->pre_cmd[i-1] + PLANB_DUMMY; - pb->pre_cmd[i] = pb->cap_cmd[i] + pb->tab_size * TAB_FACTOR; - } - pb->frame_stat=(volatile unsigned int *)(pb->pre_cmd[MAX_GBUFFERS-1] - + PLANB_DUMMY); - pb->mask = (unsigned char *)(pb->frame_stat+MAX_GBUFFERS); - - pb->rawbuf = NULL; - pb->rawbuf_size = 0; - pb->grabbing = 0; - for (i = 0; i < MAX_GBUFFERS; i++) { - pb->frame_stat[i] = GBUFFER_UNUSED; - pb->gwidth[i] = 0; - pb->gheight[i] = 0; - pb->gfmt[i] = 0; - pb->gnorm_switch[i] = 0; -#ifndef PLANB_GSCANLINE - pb->lsize[i] = 0; - pb->lnum[i] = 0; -#endif /* PLANB_GSCANLINE */ - } - pb->gcount = 0; - pb->suspend = 0; - pb->last_fr = -999; - pb->prev_last_fr = -999; - - /* Reset DMA controllers */ - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - - return 0; -} - -static void planb_prepare_close(struct planb *pb) -{ - int i; - - /* make sure the dma's are idle */ - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - /* free kernel memory of command buffers */ - if(pb->priv_space != 0) { - kfree (pb->priv_space); - pb->priv_space = 0; - pb->cmd_buff_inited = 0; - } - if(pb->rawbuf) { - for (i = 0; i < pb->rawbuf_size; i++) { - ClearPageReserved(virt_to_page(pb->rawbuf[i])); - free_pages((unsigned long)pb->rawbuf[i], 0); - } - kfree(pb->rawbuf); - } - pb->rawbuf = NULL; -} - -/*****************************/ -/* overlay support functions */ -/*****************************/ - -static inline int overlay_is_active(struct planb *pb) -{ - unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd); - unsigned int caddr = (unsigned)in_le32(&pb->planb_base->ch1.cmdptr); - - return (in_le32(&pb->overlay_last1->cmd_dep) == pb->ch1_cmd_phys) - && (caddr < (pb->ch1_cmd_phys + size)) - && (caddr >= (unsigned)pb->ch1_cmd_phys); -} - -static void overlay_start(struct planb *pb) -{ - - DEBUG("PlanB: overlay_start()\n"); - - if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { - - DEBUG("PlanB: presumably, grabbing is in progress...\n"); - - planb_dbdma_stop(&pb->planb_base->ch2); - out_le32 (&pb->planb_base->ch2.cmdptr, - virt_to_bus(pb->ch2_cmd)); - planb_dbdma_restart(&pb->planb_base->ch2); - st_le16 (&pb->ch1_cmd->command, DBDMA_NOP); - tab_cmd_dbdma(pb->last_cmd[pb->last_fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->ch1_cmd)); - eieio(); - pb->prev_last_fr = pb->last_fr; - pb->last_fr = -2; - if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { - IDEBUG("PlanB: became inactive " - "in the mean time... reactivating\n"); - planb_dbdma_stop(&pb->planb_base->ch1); - out_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->ch1_cmd)); - planb_dbdma_restart(&pb->planb_base->ch1); - } - } else { - - DEBUG("PlanB: currently idle, so can do whatever\n"); - - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - st_le32 (&pb->planb_base->ch2.cmdptr, - virt_to_bus(pb->ch2_cmd)); - st_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->ch1_cmd)); - out_le16 (&pb->ch1_cmd->command, DBDMA_NOP); - planb_dbdma_restart(&pb->planb_base->ch2); - planb_dbdma_restart(&pb->planb_base->ch1); - pb->last_fr = -1; - } - return; -} - -static void overlay_stop(struct planb *pb) -{ - DEBUG("PlanB: overlay_stop()\n"); - - if(pb->last_fr == -1) { - - DEBUG("PlanB: no grabbing, it seems...\n"); - - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - pb->last_fr = -999; - } else if(pb->last_fr == -2) { - unsigned int cmd_dep; - tab_cmd_dbdma(pb->cap_cmd[pb->prev_last_fr], DBDMA_STOP, 0); - eieio(); - cmd_dep = (unsigned int)in_le32(&pb->overlay_last1->cmd_dep); - if(overlay_is_active(pb)) { - - DEBUG("PlanB: overlay is currently active\n"); - - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - if(cmd_dep != pb->ch1_cmd_phys) { - out_le32(&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->overlay_last1)); - planb_dbdma_restart(&pb->planb_base->ch1); - } - } - pb->last_fr = pb->prev_last_fr; - pb->prev_last_fr = -999; - } - return; -} - -static void suspend_overlay(struct planb *pb) -{ - int fr = -1; - struct dbdma_cmd last; - - DEBUG("PlanB: suspend_overlay: %d\n", pb->suspend); - - if(pb->suspend++) - return; - if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { - if(pb->last_fr == -2) { - fr = pb->prev_last_fr; - memcpy(&last, (void*)pb->last_cmd[fr], sizeof(last)); - tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); - } - if(overlay_is_active(pb)) { - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - pb->suspended.overlay = 1; - pb->suspended.frame = fr; - memcpy(&pb->suspended.cmd, &last, sizeof(last)); - return; - } - } - pb->suspended.overlay = 0; - pb->suspended.frame = fr; - memcpy(&pb->suspended.cmd, &last, sizeof(last)); - return; -} - -static void resume_overlay(struct planb *pb) -{ - - DEBUG("PlanB: resume_overlay: %d\n", pb->suspend); - - if(pb->suspend > 1) - return; - if(pb->suspended.frame != -1) { - memcpy((void*)pb->last_cmd[pb->suspended.frame], - &pb->suspended.cmd, sizeof(pb->suspended.cmd)); - } - if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { - goto finish; - } - if(pb->suspended.overlay) { - - DEBUG("PlanB: overlay being resumed\n"); - - st_le16 (&pb->ch1_cmd->command, DBDMA_NOP); - st_le16 (&pb->ch2_cmd->command, DBDMA_NOP); - /* Set command buffer addresses */ - st_le32(&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->overlay_last1)); - out_le32(&pb->planb_base->ch2.cmdptr, - virt_to_bus(pb->overlay_last2)); - /* Start the DMA controller */ - out_le32 (&pb->planb_base->ch2.control, - PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); - out_le32 (&pb->planb_base->ch1.control, - PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); - } else if(pb->suspended.frame != -1) { - out_le32(&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->last_cmd[pb->suspended.frame])); - out_le32 (&pb->planb_base->ch1.control, - PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); - } - -finish: - pb->suspend--; - wake_up_interruptible(&pb->suspendq); -} - -static void add_clip(struct planb *pb, struct video_clip *clip) -{ - volatile unsigned char *base; - int xc = clip->x, yc = clip->y; - int wc = clip->width, hc = clip->height; - int ww = pb->win.width, hw = pb->win.height; - int x, y, xtmp1, xtmp2; - - DEBUG("PlanB: clip %dx%d+%d+%d\n", wc, hc, xc, yc); - - if(xc < 0) { - wc += xc; - xc = 0; - } - if(yc < 0) { - hc += yc; - yc = 0; - } - if(xc + wc > ww) - wc = ww - xc; - if(wc <= 0) /* Nothing to do */ - return; - if(yc + hc > hw) - hc = hw - yc; - - for (y = yc; y < yc+hc; y++) { - xtmp1=xc>>3; - xtmp2=(xc+wc)>>3; - base = pb->mask + y*96; - if(xc != 0 || wc >= 8) - *(base + xtmp1) &= (unsigned char)(0x00ff & - (0xff00 >> (xc&7))); - for (x = xtmp1 + 1; x < xtmp2; x++) { - *(base + x) = 0; - } - if(xc < (ww & ~0x7)) - *(base + xtmp2) &= (unsigned char)(0x00ff >> - ((xc+wc) & 7)); - } - - return; -} - -static void fill_cmd_buff(struct planb *pb) -{ - int restore = 0; - volatile struct dbdma_cmd last; - - DEBUG("PlanB: fill_cmd_buff()\n"); - - if(pb->overlay_last1 != pb->ch1_cmd) { - restore = 1; - last = *(pb->overlay_last1); - } - memset ((void *) pb->ch1_cmd, 0, 2 * pb->tab_size - * sizeof(struct dbdma_cmd)); - cmd_buff (pb); - if(restore) - *(pb->overlay_last1) = last; - if(pb->suspended.overlay) { - unsigned long jump_addr = in_le32(&pb->overlay_last1->cmd_dep); - if(jump_addr != pb->ch1_cmd_phys) { - int i; - - DEBUG("PlanB: adjusting ch1's jump address\n"); - - for(i = 0; i < MAX_GBUFFERS; i++) { - if(pb->need_pre_capture[i]) { - if(jump_addr == virt_to_bus(pb->pre_cmd[i])) - goto found; - } else { - if(jump_addr == virt_to_bus(pb->cap_cmd[i])) - goto found; - } - } - - DEBUG("PlanB: not found...\n"); - - goto out; -found: - if(pb->need_pre_capture[i]) - out_le32(&pb->pre_cmd[i]->phy_addr, - virt_to_bus(pb->overlay_last1)); - else - out_le32(&pb->cap_cmd[i]->phy_addr, - virt_to_bus(pb->overlay_last1)); - } - } -out: - pb->cmd_buff_inited = 1; - - return; -} - -static void cmd_buff(struct planb *pb) -{ - int i, bpp, count, nlines, stepsize, interlace; - unsigned long base, jump, addr_com, addr_dep; - volatile struct dbdma_cmd *c1 = pb->ch1_cmd; - volatile struct dbdma_cmd *c2 = pb->ch2_cmd; - - interlace = pb->win.interlace; - bpp = pb->win.bpp; - count = (bpp * ((pb->win.x + pb->win.width > pb->win.swidth) ? - (pb->win.swidth - pb->win.x) : pb->win.width)); - nlines = ((pb->win.y + pb->win.height > pb->win.sheight) ? - (pb->win.sheight - pb->win.y) : pb->win.height); - - /* Do video in: */ - - /* Preamble commands: */ - addr_com = virt_to_bus(c1); - addr_dep = virt_to_bus(&c1->cmd_dep); - tab_cmd_dbdma(c1++, DBDMA_NOP, 0); - jump = virt_to_bus(c1+16); /* 14 by cmd_geo_setup() and 2 for padding */ - if((c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace, - bpp, 1, pb)) == NULL) { - printk(KERN_WARNING "PlanB: encountered serious problems\n"); - tab_cmd_dbdma(pb->ch1_cmd + 1, DBDMA_STOP, 0); - tab_cmd_dbdma(pb->ch2_cmd + 1, DBDMA_STOP, 0); - return; - } - tab_cmd_store(c1++, addr_com, (unsigned)(DBDMA_NOP | BR_ALWAYS) << 16); - tab_cmd_store(c1++, addr_dep, jump); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), - PLANB_SET(FIELD_SYNC)); - /* (1) wait for field sync to be set */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - /* wait for field sync to be cleared */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - /* if not odd field, wait until field sync is set again */ - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; - /* assert ch_sync to ch2 */ - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control), - PLANB_SET(CH_SYNC)); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); - - base = (pb->frame_buffer_phys + pb->offset + pb->win.y * (pb->win.bpl - + pb->win.pad) + pb->win.x * bpp); - - if (interlace) { - stepsize = 2; - jump = virt_to_bus(c1 + (nlines + 1) / 2); - } else { - stepsize = 1; - jump = virt_to_bus(c1 + nlines); - } - - /* even field data: */ - for (i=0; i < nlines; i += stepsize, c1++) - tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, - count, base + i * (pb->win.bpl + pb->win.pad), jump); - - /* For non-interlaced, we use even fields only */ - if (!interlace) - goto cmd_tab_data_end; - - /* Resync to odd field */ - /* (2) wait for field sync to be set */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - /* wait for field sync to be cleared */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - /* if not odd field, wait until field sync is set again */ - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; - /* assert ch_sync to ch2 */ - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control), - PLANB_SET(CH_SYNC)); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); - - /* odd field data: */ - jump = virt_to_bus(c1 + nlines / 2); - for (i=1; i < nlines; i += stepsize, c1++) - tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, - base + i * (pb->win.bpl + pb->win.pad), jump); - - /* And jump back to the start */ -cmd_tab_data_end: - pb->overlay_last1 = c1; /* keep a pointer to the last command */ - tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch1_cmd)); - - /* Clipmask command buffer */ - - /* Preamble commands: */ - tab_cmd_dbdma(c2++, DBDMA_NOP, 0); - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel), - PLANB_SET(CH_SYNC)); - /* wait until ch1 asserts ch_sync */ - tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0); - /* clear ch_sync asserted by ch1 */ - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.control), - PLANB_CLR(CH_SYNC)); - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel), - PLANB_SET(FIELD_SYNC)); - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), - PLANB_SET(ODD_FIELD)); - - /* jump to end of even field if appropriate */ - /* this points to (interlace)? pos. C: pos. B */ - jump = (interlace) ? virt_to_bus(c2 + (nlines + 1) / 2 + 2): - virt_to_bus(c2 + nlines + 2); - /* if odd field, skip over to odd field clipmasking */ - tab_cmd_dbdma(c2++, DBDMA_NOP | BR_IFSET, jump); - - /* even field mask: */ - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), - PLANB_SET(DMA_ABORT)); - /* this points to pos. B */ - jump = (interlace) ? virt_to_bus(c2 + nlines + 1): - virt_to_bus(c2 + nlines); - base = virt_to_bus(pb->mask); - for (i=0; i < nlines; i += stepsize, c2++) - tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96, - base + i * 96, jump); - - /* For non-interlaced, we use only even fields */ - if(!interlace) - goto cmd_tab_mask_end; - - /* odd field mask: */ -/* C */ tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), - PLANB_SET(DMA_ABORT)); - /* this points to pos. B */ - jump = virt_to_bus(c2 + nlines / 2); - base = virt_to_bus(pb->mask); - for (i=1; i < nlines; i += 2, c2++) /* abort if set */ - tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96, - base + i * 96, jump); - - /* Inform channel 1 and jump back to start */ -cmd_tab_mask_end: - /* ok, I just realized this is kind of flawed. */ - /* this part is reached only after odd field clipmasking. */ - /* wanna clean up? */ - /* wait for field sync to be set */ - /* corresponds to fsync (1) of ch1 */ -/* B */ tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0); - /* restart ch1, meant to clear any dead bit or something */ - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control), - PLANB_CLR(RUN)); - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control), - PLANB_SET(RUN)); - pb->overlay_last2 = c2; /* keep a pointer to the last command */ - /* start over even field clipmasking */ - tab_cmd_dbdma(c2, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch2_cmd)); - - eieio(); - return; -} - -/*********************************/ -/* grabdisplay support functions */ -/*********************************/ - -static int palette2fmt[] = { - 0, - PLANB_GRAY, - 0, - 0, - 0, - PLANB_COLOUR32, - PLANB_COLOUR15, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, -}; - -#define PLANB_PALETTE_MAX 15 - -static int vgrab(struct planb *pb, struct video_mmap *mp) -{ - unsigned int fr = mp->frame; - unsigned int format; - - if(pb->rawbuf==NULL) { - int err; - if((err=grabbuf_alloc(pb))) - return err; - } - - IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing, - mp->width, mp->height, fr); - - if(pb->grabbing >= MAX_GBUFFERS) - return -ENOBUFS; - if(fr > (MAX_GBUFFERS - 1) || fr < 0) - return -EINVAL; - if(mp->height <= 0 || mp->width <= 0) - return -EINVAL; - if(mp->format < 0 || mp->format >= PLANB_PALETTE_MAX) - return -EINVAL; - if((format = palette2fmt[mp->format]) == 0) - return -EINVAL; - if (mp->height * mp->width * format > PLANB_MAX_FBUF) /* format = bpp */ - return -EINVAL; - - planb_lock(pb); - if(mp->width != pb->gwidth[fr] || mp->height != pb->gheight[fr] || - format != pb->gfmt[fr] || (pb->gnorm_switch[fr])) { - int i; -#ifndef PLANB_GSCANLINE - unsigned int osize = pb->gwidth[fr] * pb->gheight[fr] - * pb->gfmt[fr]; - unsigned int nsize = mp->width * mp->height * format; -#endif - - IDEBUG("PlanB: gwidth = %d, gheight = %d, mp->format = %u\n", - mp->width, mp->height, mp->format); - -#ifndef PLANB_GSCANLINE - if(pb->gnorm_switch[fr]) - nsize = 0; - if (nsize < osize) { - for(i = pb->gbuf_idx[fr]; osize > 0; i++) { - memset((void *)pb->rawbuf[i], 0, PAGE_SIZE); - osize -= PAGE_SIZE; - } - } - for(i = pb->l_fr_addr_idx[fr]; i < pb->l_fr_addr_idx[fr] - + pb->lnum[fr]; i++) - memset((void *)pb->rawbuf[i], 0, PAGE_SIZE); -#else -/* XXX TODO */ -/* - if(pb->gnorm_switch[fr]) - memset((void *)pb->gbuffer[fr], 0, - pb->gbytes_per_line * pb->gheight[fr]); - else { - if(mp-> - for(i = 0; i < pb->gheight[fr]; i++) { - memset((void *)(pb->gbuffer[fr] - + pb->gbytes_per_line * i - } - } -*/ -#endif - pb->gwidth[fr] = mp->width; - pb->gheight[fr] = mp->height; - pb->gfmt[fr] = format; - pb->last_cmd[fr] = setup_grab_cmd(fr, pb); - planb_pre_capture(fr, pb->gfmt[fr], pb); /* gfmt = bpp */ - pb->need_pre_capture[fr] = 1; - pb->gnorm_switch[fr] = 0; - } else - pb->need_pre_capture[fr] = 0; - pb->frame_stat[fr] = GBUFFER_GRABBING; - if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { - - IDEBUG("PlanB: ch1 inactive, initiating grabbing\n"); - - planb_dbdma_stop(&pb->planb_base->ch1); - if(pb->need_pre_capture[fr]) { - - IDEBUG("PlanB: padding pre-capture sequence\n"); - - out_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->pre_cmd[fr])); - } else { - tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); - tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); - /* let's be on the safe side. here is not timing critical. */ - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), DBDMA_NOP, 0); - out_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->cap_cmd[fr])); - } - planb_dbdma_restart(&pb->planb_base->ch1); - pb->last_fr = fr; - } else { - int i; - - IDEBUG("PlanB: ch1 active, grabbing being queued\n"); - - if((pb->last_fr == -1) || ((pb->last_fr == -2) && - overlay_is_active(pb))) { - - IDEBUG("PlanB: overlay is active, grabbing defered\n"); - - tab_cmd_dbdma(pb->last_cmd[fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->ch1_cmd)); - if(pb->need_pre_capture[fr]) { - - IDEBUG("PlanB: padding pre-capture sequence\n"); - - tab_cmd_store(pb->pre_cmd[fr], - virt_to_bus(&pb->overlay_last1->cmd_dep), - virt_to_bus(pb->ch1_cmd)); - eieio(); - out_le32 (&pb->overlay_last1->cmd_dep, - virt_to_bus(pb->pre_cmd[fr])); - } else { - tab_cmd_store(pb->cap_cmd[fr], - virt_to_bus(&pb->overlay_last1->cmd_dep), - virt_to_bus(pb->ch1_cmd)); - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), - DBDMA_NOP, 0); - eieio(); - out_le32 (&pb->overlay_last1->cmd_dep, - virt_to_bus(pb->cap_cmd[fr])); - } - for(i = 0; overlay_is_active(pb) && i < 999; i++) - IDEBUG("PlanB: waiting for overlay done\n"); - tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0); - pb->prev_last_fr = fr; - pb->last_fr = -2; - } else if(pb->last_fr == -2) { - - IDEBUG("PlanB: mixed mode detected, grabbing" - " will be done before activating overlay\n"); - - tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0); - if(pb->need_pre_capture[fr]) { - - IDEBUG("PlanB: padding pre-capture sequence\n"); - - tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->pre_cmd[fr])); - eieio(); - } else { - tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); - if(pb->gwidth[pb->prev_last_fr] != - pb->gwidth[fr] - || pb->gheight[pb->prev_last_fr] != - pb->gheight[fr] - || pb->gfmt[pb->prev_last_fr] != - pb->gfmt[fr]) - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), - DBDMA_NOP, 0); - else - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->cap_cmd[fr] + 16)); - tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->cap_cmd[fr])); - eieio(); - } - tab_cmd_dbdma(pb->last_cmd[fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->ch1_cmd)); - eieio(); - pb->prev_last_fr = fr; - pb->last_fr = -2; - } else { - - IDEBUG("PlanB: active grabbing session detected\n"); - - if(pb->need_pre_capture[fr]) { - - IDEBUG("PlanB: padding pre-capture sequence\n"); - - tab_cmd_dbdma(pb->last_cmd[pb->last_fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->pre_cmd[fr])); - eieio(); - } else { - tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); - tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); - if(pb->gwidth[pb->last_fr] != pb->gwidth[fr] - || pb->gheight[pb->last_fr] != - pb->gheight[fr] - || pb->gfmt[pb->last_fr] != - pb->gfmt[fr]) - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), - DBDMA_NOP, 0); - else - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->cap_cmd[fr] + 16)); - tab_cmd_dbdma(pb->last_cmd[pb->last_fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->cap_cmd[fr])); - eieio(); - } - pb->last_fr = fr; - } - if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { - - IDEBUG("PlanB: became inactive in the mean time..." - "reactivating\n"); - - planb_dbdma_stop(&pb->planb_base->ch1); - out_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->cap_cmd[fr])); - planb_dbdma_restart(&pb->planb_base->ch1); - } - } - pb->grabbing++; - planb_unlock(pb); - - return 0; -} - -static void planb_pre_capture(int fr, int bpp, struct planb *pb) -{ - volatile struct dbdma_cmd *c1 = pb->pre_cmd[fr]; - int interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0; - - tab_cmd_dbdma(c1++, DBDMA_NOP, 0); - if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace, - bpp, 0, pb)) == NULL) { - printk(KERN_WARNING "PlanB: encountered some problems\n"); - tab_cmd_dbdma(pb->pre_cmd[fr] + 1, DBDMA_STOP, 0); - return; - } - /* Sync to even field */ - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), - PLANB_SET(FIELD_SYNC)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; - tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); - /* For non-interlaced, we use even fields only */ - if (pb->gheight[fr] <= pb->maxlines/2) - goto cmd_tab_data_end; - /* Sync to odd field */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); -cmd_tab_data_end: - tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->cap_cmd[fr])); - - eieio(); -} - -static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb) -{ - int i, bpp, count, nlines, stepsize, interlace; -#ifdef PLANB_GSCANLINE - int scanline; -#else - int nlpp, leftover1; - unsigned long base; -#endif - unsigned long jump; - int pagei; - volatile struct dbdma_cmd *c1; - volatile struct dbdma_cmd *jump_addr; - - c1 = pb->cap_cmd[fr]; - interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0; - bpp = pb->gfmt[fr]; /* gfmt = bpp */ - count = bpp * pb->gwidth[fr]; - nlines = pb->gheight[fr]; -#ifdef PLANB_GSCANLINE - scanline = pb->gbytes_per_line; -#else - pb->lsize[fr] = count; - pb->lnum[fr] = 0; -#endif - - /* Do video in: */ - - /* Preamble commands: */ - tab_cmd_dbdma(c1++, DBDMA_NOP, 0); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(c1 + 16)); c1++; - if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace, - bpp, 0, pb)) == NULL) { - printk(KERN_WARNING "PlanB: encountered serious problems\n"); - tab_cmd_dbdma(pb->cap_cmd[fr] + 1, DBDMA_STOP, 0); - return (pb->cap_cmd[fr] + 2); - } - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), - PLANB_SET(FIELD_SYNC)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; - tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); - - if (interlace) { - stepsize = 2; - jump_addr = c1 + TAB_FACTOR * (nlines + 1) / 2; - } else { - stepsize = 1; - jump_addr = c1 + TAB_FACTOR * nlines; - } - jump = virt_to_bus(jump_addr); - - /* even field data: */ - - pagei = pb->gbuf_idx[fr]; -#ifdef PLANB_GSCANLINE - for (i = 0; i < nlines; i += stepsize) { - tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - virt_to_bus(pb->rawbuf[pagei - + i * scanline / PAGE_SIZE]), jump); - } -#else - i = 0; - leftover1 = 0; - do { - int j; - - base = virt_to_bus(pb->rawbuf[pagei]); - nlpp = (PAGE_SIZE - leftover1) / count / stepsize; - for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++) - tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, - count, base + count * j * stepsize + leftover1, jump); - if(i < nlines) { - int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1; - - if(lov0 == 0) - leftover1 = 0; - else { - if(lov0 >= count) { - tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, base - + count * nlpp * stepsize + leftover1, jump); - } else { - pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei] - + count * nlpp * stepsize + leftover1; - pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1; - pb->l_to_next_size[fr][pb->lnum[fr]] = count - lov0; - tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr] - + pb->lnum[fr]]), jump); - if(++pb->lnum[fr] > MAX_LNUM) - pb->lnum[fr]--; - } - leftover1 = count * stepsize - lov0; - i += stepsize; - } - } - pagei++; - } while(i < nlines); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump); - c1 = jump_addr; -#endif /* PLANB_GSCANLINE */ - - /* For non-interlaced, we use even fields only */ - if (!interlace) - goto cmd_tab_data_end; - - /* Sync to odd field */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); - - /* odd field data: */ - jump_addr = c1 + TAB_FACTOR * nlines / 2; - jump = virt_to_bus(jump_addr); -#ifdef PLANB_GSCANLINE - for (i = 1; i < nlines; i += stepsize) { - tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - virt_to_bus(pb->rawbuf[pagei - + i * scanline / PAGE_SIZE]), jump); - } -#else - i = 1; - leftover1 = 0; - pagei = pb->gbuf_idx[fr]; - if(nlines <= 1) - goto skip; - do { - int j; - - base = virt_to_bus(pb->rawbuf[pagei]); - nlpp = (PAGE_SIZE - leftover1) / count / stepsize; - if(leftover1 >= count) { - tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, - base + leftover1 - count, jump); - i += stepsize; - } - for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++) - tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, - base + count * (j * stepsize + 1) + leftover1, jump); - if(i < nlines) { - int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1; - - if(lov0 == 0) - leftover1 = 0; - else { - if(lov0 > count) { - pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei] - + count * (nlpp * stepsize + 1) + leftover1; - pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1; - pb->l_to_next_size[fr][pb->lnum[fr]] = count * stepsize - - lov0; - tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr] - + pb->lnum[fr]]), jump); - if(++pb->lnum[fr] > MAX_LNUM) - pb->lnum[fr]--; - i += stepsize; - } - leftover1 = count * stepsize - lov0; - } - } - pagei++; - } while(i < nlines); -skip: - tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump); - c1 = jump_addr; -#endif /* PLANB_GSCANLINE */ - -cmd_tab_data_end: - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->intr_stat), - (fr << 9) | PLANB_FRM_IRQ | PLANB_GEN_IRQ); - /* stop it */ - tab_cmd_dbdma(c1, DBDMA_STOP, 0); - - eieio(); - return c1; -} - -static irqreturn_t planb_irq(int irq, void *dev_id) -{ - unsigned int stat, astat; - struct planb *pb = (struct planb *)dev_id; - - IDEBUG("PlanB: planb_irq()\n"); - - /* get/clear interrupt status bits */ - eieio(); - stat = in_le32(&pb->planb_base->intr_stat); - astat = stat & pb->intr_mask; - out_le32(&pb->planb_base->intr_stat, PLANB_FRM_IRQ - & ~astat & stat & ~PLANB_GEN_IRQ); - IDEBUG("PlanB: stat = %X, astat = %X\n", stat, astat); - - if(astat & PLANB_FRM_IRQ) { - unsigned int fr = stat >> 9; -#ifndef PLANB_GSCANLINE - int i; -#endif - IDEBUG("PlanB: PLANB_FRM_IRQ\n"); - - pb->gcount++; - - IDEBUG("PlanB: grab %d: fr = %d, gcount = %d\n", - pb->grabbing, fr, pb->gcount); -#ifndef PLANB_GSCANLINE - IDEBUG("PlanB: %d * %d bytes are being copied over\n", - pb->lnum[fr], pb->lsize[fr]); - for(i = 0; i < pb->lnum[fr]; i++) { - int first = pb->lsize[fr] - pb->l_to_next_size[fr][i]; - - memcpy(pb->l_to_addr[fr][i], - pb->rawbuf[pb->l_fr_addr_idx[fr] + i], - first); - memcpy(pb->rawbuf[pb->l_to_next_idx[fr][i]], - pb->rawbuf[pb->l_fr_addr_idx[fr] + i] + first, - pb->l_to_next_size[fr][i]); - } -#endif - pb->frame_stat[fr] = GBUFFER_DONE; - pb->grabbing--; - wake_up_interruptible(&pb->capq); - return IRQ_HANDLED; - } - /* incorrect interrupts? */ - pb->intr_mask = PLANB_CLR_IRQ; - out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ); - printk(KERN_ERR "PlanB: IRQ lockup, cleared intrrupts" - " unconditionally\n"); - return IRQ_HANDLED; -} - -/******************************* - * Device Operations functions * - *******************************/ - -static int planb_open(struct video_device *dev, int mode) -{ - struct planb *pb = (struct planb *)dev; - - if (pb->user == 0) { - int err; - if((err = planb_prepare_open(pb)) != 0) - return err; - } - pb->user++; - - DEBUG("PlanB: device opened\n"); - return 0; -} - -static void planb_close(struct video_device *dev) -{ - struct planb *pb = (struct planb *)dev; - - if(pb->user < 1) /* ??? */ - return; - planb_lock(pb); - if (pb->user == 1) { - if (pb->overlay) { - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - pb->overlay = 0; - } - planb_prepare_close(pb); - } - pb->user--; - planb_unlock(pb); - - DEBUG("PlanB: device closed\n"); -} - -static long planb_read(struct video_device *v, char *buf, unsigned long count, - int nonblock) -{ - DEBUG("planb: read request\n"); - return -EINVAL; -} - -static long planb_write(struct video_device *v, const char *buf, - unsigned long count, int nonblock) -{ - DEBUG("planb: write request\n"); - return -EINVAL; -} - -static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct planb *pb=(struct planb *)dev; - - switch (cmd) - { - case VIDIOCGCAP: - { - struct video_capability b; - - DEBUG("PlanB: IOCTL VIDIOCGCAP\n"); - - strcpy (b.name, pb->video_dev.name); - b.type = VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | - VID_TYPE_FRAMERAM | VID_TYPE_SCALES | - VID_TYPE_CAPTURE; - b.channels = 2; /* composite & svhs */ - b.audios = 0; - b.maxwidth = PLANB_MAXPIXELS; - b.maxheight = PLANB_MAXLINES; - b.minwidth = 32; /* wild guess */ - b.minheight = 32; - if (copy_to_user(arg,&b,sizeof(b))) - return -EFAULT; - return 0; - } - case VIDIOCSFBUF: - { - struct video_buffer v; - unsigned short bpp; - unsigned int fmt; - - DEBUG("PlanB: IOCTL VIDIOCSFBUF\n"); - - if (!capable(CAP_SYS_ADMIN) - || !capable(CAP_SYS_RAWIO)) - return -EPERM; - if (copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - planb_lock(pb); - switch(v.depth) { - case 8: - bpp = 1; - fmt = PLANB_GRAY; - break; - case 15: - case 16: - bpp = 2; - fmt = PLANB_COLOUR15; - break; - case 24: - case 32: - bpp = 4; - fmt = PLANB_COLOUR32; - break; - default: - planb_unlock(pb); - return -EINVAL; - } - if (bpp * v.width > v.bytesperline) { - planb_unlock(pb); - return -EINVAL; - } - pb->win.bpp = bpp; - pb->win.color_fmt = fmt; - pb->frame_buffer_phys = (unsigned long) v.base; - pb->win.sheight = v.height; - pb->win.swidth = v.width; - pb->picture.depth = pb->win.depth = v.depth; - pb->win.bpl = pb->win.bpp * pb->win.swidth; - pb->win.pad = v.bytesperline - pb->win.bpl; - - DEBUG("PlanB: Display at %p is %d by %d, bytedepth %d," - " bpl %d (+ %d)\n", v.base, v.width,v.height, - pb->win.bpp, pb->win.bpl, pb->win.pad); - - pb->cmd_buff_inited = 0; - if(pb->overlay) { - suspend_overlay(pb); - fill_cmd_buff(pb); - resume_overlay(pb); - } - planb_unlock(pb); - return 0; - } - case VIDIOCGFBUF: - { - struct video_buffer v; - - DEBUG("PlanB: IOCTL VIDIOCGFBUF\n"); - - v.base = (void *)pb->frame_buffer_phys; - v.height = pb->win.sheight; - v.width = pb->win.swidth; - v.depth = pb->win.depth; - v.bytesperline = pb->win.bpl + pb->win.pad; - if (copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCCAPTURE: - { - int i; - - if(copy_from_user(&i, arg, sizeof(i))) - return -EFAULT; - if(i==0) { - DEBUG("PlanB: IOCTL VIDIOCCAPTURE Stop\n"); - - if (!(pb->overlay)) - return 0; - planb_lock(pb); - pb->overlay = 0; - overlay_stop(pb); - planb_unlock(pb); - } else { - DEBUG("PlanB: IOCTL VIDIOCCAPTURE Start\n"); - - if (pb->frame_buffer_phys == 0 || - pb->win.width == 0 || - pb->win.height == 0) - return -EINVAL; - if (pb->overlay) - return 0; - planb_lock(pb); - pb->overlay = 1; - if(!(pb->cmd_buff_inited)) - fill_cmd_buff(pb); - overlay_start(pb); - planb_unlock(pb); - } - return 0; - } - case VIDIOCGCHAN: - { - struct video_channel v; - - DEBUG("PlanB: IOCTL VIDIOCGCHAN\n"); - - if(copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - v.flags = 0; - v.tuners = 0; - v.type = VIDEO_TYPE_CAMERA; - v.norm = pb->win.norm; - switch(v.channel) - { - case 0: - strcpy(v.name,"Composite"); - break; - case 1: - strcpy(v.name,"SVHS"); - break; - default: - return -EINVAL; - break; - } - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - - return 0; - } - case VIDIOCSCHAN: - { - struct video_channel v; - - DEBUG("PlanB: IOCTL VIDIOCSCHAN\n"); - - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - - if (v.norm != pb->win.norm) { - int i, maxlines; - - switch (v.norm) - { - case VIDEO_MODE_PAL: - case VIDEO_MODE_SECAM: - maxlines = PLANB_MAXLINES; - break; - case VIDEO_MODE_NTSC: - maxlines = PLANB_NTSC_MAXLINES; - break; - default: - return -EINVAL; - break; - } - planb_lock(pb); - /* empty the grabbing queue */ - wait_event(pb->capq, !pb->grabbing); - pb->maxlines = maxlines; - pb->win.norm = v.norm; - /* Stop overlay if running */ - suspend_overlay(pb); - for(i = 0; i < MAX_GBUFFERS; i++) - pb->gnorm_switch[i] = 1; - /* I know it's an overkill, but.... */ - fill_cmd_buff(pb); - /* ok, now init it accordingly */ - saa_init_regs (pb); - /* restart overlay if it was running */ - resume_overlay(pb); - planb_unlock(pb); - } - - switch(v.channel) - { - case 0: /* Composite */ - saa_set (SAA7196_IOCC, - ((saa_regs[pb->win.norm][SAA7196_IOCC] & - ~7) | 3), pb); - break; - case 1: /* SVHS */ - saa_set (SAA7196_IOCC, - ((saa_regs[pb->win.norm][SAA7196_IOCC] & - ~7) | 4), pb); - break; - default: - return -EINVAL; - break; - } - - return 0; - } - case VIDIOCGPICT: - { - struct video_picture vp = pb->picture; - - DEBUG("PlanB: IOCTL VIDIOCGPICT\n"); - - switch(pb->win.color_fmt) { - case PLANB_GRAY: - vp.palette = VIDEO_PALETTE_GREY; - case PLANB_COLOUR15: - vp.palette = VIDEO_PALETTE_RGB555; - break; - case PLANB_COLOUR32: - vp.palette = VIDEO_PALETTE_RGB32; - break; - default: - vp.palette = 0; - break; - } - - if(copy_to_user(arg,&vp,sizeof(vp))) - return -EFAULT; - return 0; - } - case VIDIOCSPICT: - { - struct video_picture vp; - - DEBUG("PlanB: IOCTL VIDIOCSPICT\n"); - - if(copy_from_user(&vp,arg,sizeof(vp))) - return -EFAULT; - pb->picture = vp; - /* Should we do sanity checks here? */ - saa_set (SAA7196_BRIG, (unsigned char) - ((pb->picture.brightness) >> 8), pb); - saa_set (SAA7196_HUEC, (unsigned char) - ((pb->picture.hue) >> 8) ^ 0x80, pb); - saa_set (SAA7196_CSAT, (unsigned char) - ((pb->picture.colour) >> 9), pb); - saa_set (SAA7196_CONT, (unsigned char) - ((pb->picture.contrast) >> 9), pb); - - return 0; - } - case VIDIOCSWIN: - { - struct video_window vw; - struct video_clip clip; - int i; - - DEBUG("PlanB: IOCTL VIDIOCSWIN\n"); - - if(copy_from_user(&vw,arg,sizeof(vw))) - return -EFAULT; - - planb_lock(pb); - /* Stop overlay if running */ - suspend_overlay(pb); - pb->win.interlace = (vw.height > pb->maxlines/2)? 1: 0; - if (pb->win.x != vw.x || - pb->win.y != vw.y || - pb->win.width != vw.width || - pb->win.height != vw.height || - !pb->cmd_buff_inited) { - pb->win.x = vw.x; - pb->win.y = vw.y; - pb->win.width = vw.width; - pb->win.height = vw.height; - fill_cmd_buff(pb); - } - /* Reset clip mask */ - memset ((void *) pb->mask, 0xff, (pb->maxlines - * ((PLANB_MAXPIXELS + 7) & ~7)) / 8); - /* Add any clip rects */ - for (i = 0; i < vw.clipcount; i++) { - if (copy_from_user(&clip, vw.clips + i, - sizeof(struct video_clip))) - return -EFAULT; - add_clip(pb, &clip); - } - /* restart overlay if it was running */ - resume_overlay(pb); - planb_unlock(pb); - return 0; - } - case VIDIOCGWIN: - { - struct video_window vw; - - DEBUG("PlanB: IOCTL VIDIOCGWIN\n"); - - vw.x=pb->win.x; - vw.y=pb->win.y; - vw.width=pb->win.width; - vw.height=pb->win.height; - vw.chromakey=0; - vw.flags=0; - if(pb->win.interlace) - vw.flags|=VIDEO_WINDOW_INTERLACE; - if(copy_to_user(arg,&vw,sizeof(vw))) - return -EFAULT; - return 0; - } - case VIDIOCSYNC: { - int i; - - IDEBUG("PlanB: IOCTL VIDIOCSYNC\n"); - - if(copy_from_user((void *)&i,arg,sizeof(int))) - return -EFAULT; - - IDEBUG("PlanB: sync to frame %d\n", i); - - if(i > (MAX_GBUFFERS - 1) || i < 0) - return -EINVAL; -chk_grab: - switch (pb->frame_stat[i]) { - case GBUFFER_UNUSED: - return -EINVAL; - case GBUFFER_GRABBING: - IDEBUG("PlanB: waiting for grab" - " done (%d)\n", i); - interruptible_sleep_on(&pb->capq); - if(signal_pending(current)) - return -EINTR; - goto chk_grab; - case GBUFFER_DONE: - pb->frame_stat[i] = GBUFFER_UNUSED; - break; - } - return 0; - } - - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - volatile unsigned int status; - - IDEBUG("PlanB: IOCTL VIDIOCMCAPTURE\n"); - - if(copy_from_user((void *) &vm,(void *)arg,sizeof(vm))) - return -EFAULT; - status = pb->frame_stat[vm.frame]; - if (status != GBUFFER_UNUSED) - return -EBUSY; - - return vgrab(pb, &vm); - } - - case VIDIOCGMBUF: - { - int i; - struct video_mbuf vm; - - DEBUG("PlanB: IOCTL VIDIOCGMBUF\n"); - - memset(&vm, 0 , sizeof(vm)); - vm.size = PLANB_MAX_FBUF * MAX_GBUFFERS; - vm.frames = MAX_GBUFFERS; - for(i = 0; i= SAA7196_NUMREGS) - return -EINVAL; - preg.val = saa_regs[pb->win.norm][preg.addr]; - if(copy_to_user((void *)arg, (void *)&preg, - sizeof(preg))) - return -EFAULT; - return 0; - } - - case PLANBIOCSSAAREGS: - { - struct planb_saa_regs preg; - - DEBUG("PlanB: IOCTL PLANBIOCSSAAREGS\n"); - - if(copy_from_user(&preg, arg, sizeof(preg))) - return -EFAULT; - if(preg.addr >= SAA7196_NUMREGS) - return -EINVAL; - saa_set (preg.addr, preg.val, pb); - return 0; - } - - case PLANBIOCGSTAT: - { - struct planb_stat_regs pstat; - - DEBUG("PlanB: IOCTL PLANBIOCGSTAT\n"); - - pstat.ch1_stat = in_le32(&pb->planb_base->ch1.status); - pstat.ch2_stat = in_le32(&pb->planb_base->ch2.status); - pstat.saa_stat0 = saa_status(0, pb); - pstat.saa_stat1 = saa_status(1, pb); - - if(copy_to_user((void *)arg, (void *)&pstat, - sizeof(pstat))) - return -EFAULT; - return 0; - } - - case PLANBIOCSMODE: { - int v; - - DEBUG("PlanB: IOCTL PLANBIOCSMODE\n"); - - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - - switch(v) - { - case PLANB_TV_MODE: - saa_set (SAA7196_STDC, - (saa_regs[pb->win.norm][SAA7196_STDC] & - 0x7f), pb); - break; - case PLANB_VTR_MODE: - saa_set (SAA7196_STDC, - (saa_regs[pb->win.norm][SAA7196_STDC] | - 0x80), pb); - break; - default: - return -EINVAL; - break; - } - pb->win.mode = v; - return 0; - } - case PLANBIOCGMODE: { - int v=pb->win.mode; - - DEBUG("PlanB: IOCTL PLANBIOCGMODE\n"); - - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } -#ifdef PLANB_GSCANLINE - case PLANBG_GRAB_BPL: { - int v=pb->gbytes_per_line; - - DEBUG("PlanB: IOCTL PLANBG_GRAB_BPL\n"); - - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } -#endif /* PLANB_GSCANLINE */ - case PLANB_INTR_DEBUG: { - int i; - - DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n"); - - if(copy_from_user(&i, arg, sizeof(i))) - return -EFAULT; - - /* avoid hang ups all together */ - for (i = 0; i < MAX_GBUFFERS; i++) { - if(pb->frame_stat[i] == GBUFFER_GRABBING) { - pb->frame_stat[i] = GBUFFER_DONE; - } - } - if(pb->grabbing) - pb->grabbing--; - wake_up_interruptible(&pb->capq); - return 0; - } - case PLANB_INV_REGS: { - int i; - struct planb_any_regs any; - - DEBUG("PlanB: IOCTL PLANB_INV_REGS\n"); - - if(copy_from_user(&any, arg, sizeof(any))) - return -EFAULT; - if(any.offset < 0 || any.offset + any.bytes > 0x400) - return -EINVAL; - if(any.bytes > 128) - return -EINVAL; - for (i = 0; i < any.bytes; i++) { - any.data[i] = - in_8((unsigned char *)pb->planb_base - + any.offset + i); - } - if(copy_to_user(arg,&any,sizeof(any))) - return -EFAULT; - return 0; - } - default: - { - DEBUG("PlanB: Unimplemented IOCTL\n"); - return -ENOIOCTLCMD; - } - /* Some IOCTLs are currently unsupported on PlanB */ - case VIDIOCGTUNER: { - DEBUG("PlanB: IOCTL VIDIOCGTUNER\n"); - goto unimplemented; } - case VIDIOCSTUNER: { - DEBUG("PlanB: IOCTL VIDIOCSTUNER\n"); - goto unimplemented; } - case VIDIOCSFREQ: { - DEBUG("PlanB: IOCTL VIDIOCSFREQ\n"); - goto unimplemented; } - case VIDIOCGFREQ: { - DEBUG("PlanB: IOCTL VIDIOCGFREQ\n"); - goto unimplemented; } - case VIDIOCKEY: { - DEBUG("PlanB: IOCTL VIDIOCKEY\n"); - goto unimplemented; } - case VIDIOCSAUDIO: { - DEBUG("PlanB: IOCTL VIDIOCSAUDIO\n"); - goto unimplemented; } - case VIDIOCGAUDIO: { - DEBUG("PlanB: IOCTL VIDIOCGAUDIO\n"); - goto unimplemented; } -unimplemented: - DEBUG(" Unimplemented\n"); - return -ENOIOCTLCMD; - } - return 0; -} - -static int planb_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size) -{ - int i; - struct planb *pb = (struct planb *)dev; - unsigned long start = (unsigned long)adr; - - if (size > MAX_GBUFFERS * PLANB_MAX_FBUF) - return -EINVAL; - if (!pb->rawbuf) { - int err; - if((err=grabbuf_alloc(pb))) - return err; - } - for (i = 0; i < pb->rawbuf_size; i++) { - unsigned long pfn; - - pfn = virt_to_phys((void *)pb->rawbuf[i]) >> PAGE_SHIFT; - if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start += PAGE_SIZE; - if (size <= PAGE_SIZE) - break; - size -= PAGE_SIZE; - } - return 0; -} - -static struct video_device planb_template= -{ - .owner = THIS_MODULE, - .name = PLANB_DEVICE_NAME, - .type = VID_TYPE_OVERLAY, - .open = planb_open, - .close = planb_close, - .read = planb_read, - .write = planb_write, - .ioctl = planb_ioctl, - .mmap = planb_mmap, /* mmap? */ -}; - -static int init_planb(struct planb *pb) -{ - unsigned char saa_rev; - int i, result; - - memset ((void *) &pb->win, 0, sizeof (struct planb_window)); - /* Simple sanity check */ - if(def_norm >= NUM_SUPPORTED_NORM || def_norm < 0) { - printk(KERN_ERR "PlanB: Option(s) invalid\n"); - return -2; - } - pb->win.norm = def_norm; - pb->win.mode = PLANB_TV_MODE; /* TV mode */ - pb->win.interlace=1; - pb->win.x=0; - pb->win.y=0; - pb->win.width=768; /* 640 */ - pb->win.height=576; /* 480 */ - pb->maxlines=576; -#if 0 - btv->win.cropwidth=768; /* 640 */ - btv->win.cropheight=576; /* 480 */ - btv->win.cropx=0; - btv->win.cropy=0; -#endif - pb->win.pad=0; - pb->win.bpp=4; - pb->win.depth=32; - pb->win.color_fmt=PLANB_COLOUR32; - pb->win.bpl=1024*pb->win.bpp; - pb->win.swidth=1024; - pb->win.sheight=768; -#ifdef PLANB_GSCANLINE - if((pb->gbytes_per_line = PLANB_MAXPIXELS * 4) > PAGE_SIZE - || (pb->gbytes_per_line <= 0)) - return -3; - else { - /* page align pb->gbytes_per_line for DMA purpose */ - for(i = PAGE_SIZE; pb->gbytes_per_line < (i>>1);) - i>>=1; - pb->gbytes_per_line = i; - } -#endif - pb->tab_size = PLANB_MAXLINES + 40; - pb->suspend = 0; - mutex_init(&pb->lock); - pb->ch1_cmd = 0; - pb->ch2_cmd = 0; - pb->mask = 0; - pb->priv_space = 0; - pb->offset = 0; - pb->user = 0; - pb->overlay = 0; - init_waitqueue_head(&pb->suspendq); - pb->cmd_buff_inited = 0; - pb->frame_buffer_phys = 0; - - /* Reset DMA controllers */ - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - - saa_rev = (saa_status(0, pb) & 0xf0) >> 4; - printk(KERN_INFO "PlanB: SAA7196 video processor rev. %d\n", saa_rev); - /* Initialize the SAA registers in memory and on chip */ - saa_init_regs (pb); - - /* clear interrupt mask */ - pb->intr_mask = PLANB_CLR_IRQ; - - result = request_irq(pb->irq, planb_irq, 0, "PlanB", pb); - if (result < 0) { - if (result==-EINVAL) - printk(KERN_ERR "PlanB: Bad irq number (%d) " - "or handler\n", (int)pb->irq); - else if (result==-EBUSY) - printk(KERN_ERR "PlanB: I don't know why, " - "but IRQ %d is busy\n", (int)pb->irq); - return result; - } - disable_irq(pb->irq); - - /* Now add the template and register the device unit. */ - memcpy(&pb->video_dev,&planb_template,sizeof(planb_template)); - - pb->picture.brightness=0x90<<8; - pb->picture.contrast = 0x70 << 8; - pb->picture.colour = 0x70<<8; - pb->picture.hue = 0x8000; - pb->picture.whiteness = 0; - pb->picture.depth = pb->win.depth; - - pb->frame_stat=NULL; - init_waitqueue_head(&pb->capq); - for(i=0; igbuf_idx[i] = PLANB_MAX_FBUF * i / PAGE_SIZE; - pb->gwidth[i]=0; - pb->gheight[i]=0; - pb->gfmt[i]=0; - pb->cap_cmd[i]=NULL; -#ifndef PLANB_GSCANLINE - pb->l_fr_addr_idx[i] = MAX_GBUFFERS * (PLANB_MAX_FBUF - / PAGE_SIZE + 1) + MAX_LNUM * i; - pb->lsize[i] = 0; - pb->lnum[i] = 0; -#endif - } - pb->rawbuf=NULL; - pb->grabbing=0; - - /* enable interrupts */ - out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ); - pb->intr_mask = PLANB_FRM_IRQ; - enable_irq(pb->irq); - - if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER, video_nr)<0) - return -1; - - return 0; -} - -/* - * Scan for a PlanB controller, request the irq and map the io memory - */ - -static int find_planb(void) -{ - struct planb *pb; - struct device_node *planb_devices; - unsigned char dev_fn, confreg, bus; - unsigned int old_base, new_base; - unsigned int irq; - struct pci_dev *pdev; - int rc; - - if (!machine_is(powermac)) - return 0; - - planb_devices = of_find_node_by_name(NULL, "planb"); - if (planb_devices == 0) { - planb_num=0; - printk(KERN_WARNING "PlanB: no device found!\n"); - return planb_num; - } - - if (planb_devices->next != NULL) - printk(KERN_ERR "Warning: only using first PlanB device!\n"); - pb = &planbs[0]; - planb_num = 1; - - if (planb_devices->n_addrs != 1) { - printk (KERN_WARNING "PlanB: expecting 1 address for planb " - "(got %d)", planb_devices->n_addrs); - of_node_put(planb_devices); - return 0; - } - - if (planb_devices->n_intrs == 0) { - printk(KERN_WARNING "PlanB: no intrs for device %s\n", - planb_devices->full_name); - of_node_put(planb_devices); - return 0; - } else { - irq = planb_devices->intrs[0].line; - } - - /* Initialize PlanB's PCI registers */ - - /* There is a bug with the way OF assigns addresses - to the devices behind the chaos bridge. - control needs only 0x1000 of space, but decodes only - the upper 16 bits. It therefore occupies a full 64K. - OF assigns the planb controller memory within this space; - so we need to change that here in order to access planb. */ - - /* We remap to 0xf1000000 in hope that nobody uses it ! */ - - bus = (planb_devices->addrs[0].space >> 16) & 0xff; - dev_fn = (planb_devices->addrs[0].space >> 8) & 0xff; - confreg = planb_devices->addrs[0].space & 0xff; - old_base = planb_devices->addrs[0].address; - new_base = 0xf1000000; - of_node_put(planb_devices); - - DEBUG("PlanB: Found on bus %d, dev %d, func %d, " - "membase 0x%x (base reg. 0x%x)\n", - bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg); - - pdev = pci_get_bus_and_slot(bus, dev_fn); - if (!pdev) { - printk(KERN_ERR "planb: cannot find slot\n"); - goto err_out; - } - - /* Enable response in memory space, bus mastering, - use memory write and invalidate */ - rc = pci_enable_device(pdev); - if (rc) { - printk(KERN_ERR "planb: cannot enable PCI device %s\n", - pci_name(pdev)); - goto err_out; - } - rc = pci_set_mwi(pdev); - if (rc) { - printk(KERN_ERR "planb: cannot enable MWI on PCI device %s\n", - pci_name(pdev)); - goto err_out_disable; - } - pci_set_master(pdev); - - /* Set the new base address */ - pci_write_config_dword (pdev, confreg, new_base); - - planb_regs = (volatile struct planb_registers *) - ioremap (new_base, 0x400); - pb->planb_base = planb_regs; - pb->planb_base_phys = (struct planb_registers *)new_base; - pb->irq = irq; - pb->dev = pdev; - - return planb_num; - -err_out_disable: - pci_disable_device(pdev); -err_out: - /* FIXME handle error */ /* comment moved from pci_find_slot, above */ - pci_dev_put(pdev); - return 0; -} - -static void release_planb(void) -{ - int i; - struct planb *pb; - - for (i=0;iplanb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - - /* clear and free interrupts */ - pb->intr_mask = PLANB_CLR_IRQ; - out_le32 (&pb->planb_base->intr_stat, PLANB_CLR_IRQ); - free_irq(pb->irq, pb); - - /* make sure all allocated memory are freed */ - planb_prepare_close(pb); - - printk(KERN_INFO "PlanB: unregistering with v4l\n"); - video_unregister_device(&pb->video_dev); - - pci_dev_put(pb->dev); - - /* note that iounmap() does nothing on the PPC right now */ - iounmap ((void *)pb->planb_base); - } -} - -static int __init init_planbs(void) -{ - int i; - - if (find_planb()<=0) - return -EIO; - - for (i=0; i -#include "saa7196.h" -#endif /* __KERNEL__ */ - -#define PLANB_DEVICE_NAME "Apple PlanB Video-In" -#define PLANB_REV "1.0" - -#ifdef __KERNEL__ -//#define PLANB_GSCANLINE /* use this if apps have the notion of */ - /* grab buffer scanline */ -/* This should be safe for both PAL and NTSC */ -#define PLANB_MAXPIXELS 768 -#define PLANB_MAXLINES 576 -#define PLANB_NTSC_MAXLINES 480 - -/* Uncomment your preferred norm ;-) */ -#define PLANB_DEF_NORM VIDEO_MODE_PAL -//#define PLANB_DEF_NORM VIDEO_MODE_NTSC -//#define PLANB_DEF_NORM VIDEO_MODE_SECAM - -/* fields settings */ -#define PLANB_GRAY 0x1 /* 8-bit mono? */ -#define PLANB_COLOUR15 0x2 /* 16-bit mode */ -#define PLANB_COLOUR32 0x4 /* 32-bit mode */ -#define PLANB_CLIPMASK 0x8 /* hardware clipmasking */ - -/* misc. flags for PlanB DMA operation */ -#define CH_SYNC 0x1 /* synchronize channels (set by ch1; - cleared by ch2) */ -#define FIELD_SYNC 0x2 /* used for the start of each field - (0 -> 1 -> 0 for ch1; 0 -> 1 for ch2) */ -#define EVEN_FIELD 0x0 /* even field is detected if unset */ -#define DMA_ABORT 0x2 /* error or just out of sync if set */ -#define ODD_FIELD 0x4 /* odd field is detected if set */ - -/* for capture operations */ -#define MAX_GBUFFERS 2 -/* note PLANB_MAX_FBUF must be divisible by PAGE_SIZE */ -#ifdef PLANB_GSCANLINE -#define PLANB_MAX_FBUF 0x240000 /* 576 * 1024 * 4 */ -#define TAB_FACTOR (1) -#else -#define PLANB_MAX_FBUF 0x1b0000 /* 576 * 768 * 4 */ -#define TAB_FACTOR (2) -#endif -#endif /* __KERNEL__ */ - -struct planb_saa_regs { - unsigned char addr; - unsigned char val; -}; - -struct planb_stat_regs { - unsigned int ch1_stat; - unsigned int ch2_stat; - unsigned char saa_stat0; - unsigned char saa_stat1; -}; - -struct planb_any_regs { - unsigned int offset; - unsigned int bytes; - unsigned char data[128]; -}; - -/* planb private ioctls */ -#define PLANBIOCGSAAREGS _IOWR('v', BASE_VIDIOCPRIVATE, struct planb_saa_regs) /* Read a saa7196 reg value */ -#define PLANBIOCSSAAREGS _IOW('v', BASE_VIDIOCPRIVATE + 1, struct planb_saa_regs) /* Set a saa7196 reg value */ -#define PLANBIOCGSTAT _IOR('v', BASE_VIDIOCPRIVATE + 2, struct planb_stat_regs) /* Read planb status */ -#define PLANB_TV_MODE 1 -#define PLANB_VTR_MODE 2 -#define PLANBIOCGMODE _IOR('v', BASE_VIDIOCPRIVATE + 3, int) /* Get TV/VTR mode */ -#define PLANBIOCSMODE _IOW('v', BASE_VIDIOCPRIVATE + 4, int) /* Set TV/VTR mode */ - -#ifdef PLANB_GSCANLINE -#define PLANBG_GRAB_BPL _IOR('v', BASE_VIDIOCPRIVATE + 5, int) /* # of bytes per scanline in grab buffer */ -#endif - -/* call wake_up_interruptible() with appropriate actions */ -#define PLANB_INTR_DEBUG _IOW('v', BASE_VIDIOCPRIVATE + 20, int) -/* investigate which reg does what */ -#define PLANB_INV_REGS _IOWR('v', BASE_VIDIOCPRIVATE + 21, struct planb_any_regs) - -#ifdef __KERNEL__ - -/* Potentially useful macros */ -#define PLANB_SET(x) ((x) << 16 | (x)) -#define PLANB_CLR(x) ((x) << 16) - -/* This represents the physical register layout */ -struct planb_registers { - volatile struct dbdma_regs ch1; /* 0x00: video in */ - volatile unsigned int even; /* 0x40: even field setting */ - volatile unsigned int odd; /* 0x44; odd field setting */ - unsigned int pad1[14]; /* empty? */ - volatile struct dbdma_regs ch2; /* 0x80: clipmask out */ - unsigned int pad2[16]; /* 0xc0: empty? */ - volatile unsigned int reg3; /* 0x100: ???? */ - volatile unsigned int intr_stat; /* 0x104: irq status */ -#define PLANB_CLR_IRQ 0x00 /* clear Plan B interrupt */ -#define PLANB_GEN_IRQ 0x01 /* assert Plan B interrupt */ -#define PLANB_FRM_IRQ 0x0100 /* end of frame */ - unsigned int pad3[1]; /* empty? */ - volatile unsigned int reg5; /* 0x10c: ??? */ - unsigned int pad4[60]; /* empty? */ - volatile unsigned char saa_addr; /* 0x200: SAA subadr */ - char pad5[3]; - volatile unsigned char saa_regval; /* SAA7196 write reg. val */ - char pad6[3]; - volatile unsigned char saa_status; /* SAA7196 status byte */ - /* There is more unused stuff here */ -}; - -struct planb_window { - int x, y; - ushort width, height; - ushort bpp, bpl, depth, pad; - ushort swidth, sheight; - int norm; - int interlace; - u32 color_fmt; - int chromakey; - int mode; /* used to switch between TV/VTR modes */ -}; - -struct planb_suspend { - int overlay; - int frame; - struct dbdma_cmd cmd; -}; - -struct planb { - struct video_device video_dev; - struct video_picture picture; /* Current picture params */ - struct video_audio audio_dev; /* Current audio params */ - - volatile struct planb_registers *planb_base; /* virt base of planb */ - struct planb_registers *planb_base_phys; /* phys base of planb */ - void *priv_space; /* Org. alloc. mem for kfree */ - int user; - unsigned int tab_size; - int maxlines; - struct mutex lock; - unsigned int irq; /* interrupt number */ - volatile unsigned int intr_mask; - struct pci_dev *dev; /* Our PCI device */ - - int overlay; /* overlay running? */ - struct planb_window win; - unsigned long frame_buffer_phys; /* We need phys for DMA */ - int offset; /* offset of pixel 1 */ - volatile struct dbdma_cmd *ch1_cmd; /* Video In DMA cmd buffer */ - volatile struct dbdma_cmd *ch2_cmd; /* Clip Out DMA cmd buffer */ - volatile struct dbdma_cmd *overlay_last1; - volatile struct dbdma_cmd *overlay_last2; - unsigned long ch1_cmd_phys; - volatile unsigned char *mask; /* Clipmask buffer */ - int suspend; - wait_queue_head_t suspendq; - struct planb_suspend suspended; - int cmd_buff_inited; /* cmd buffer inited? */ - - int grabbing; - unsigned int gcount; - wait_queue_head_t capq; - int last_fr; - int prev_last_fr; - unsigned char **rawbuf; - int rawbuf_size; - int gbuf_idx[MAX_GBUFFERS]; - volatile struct dbdma_cmd *cap_cmd[MAX_GBUFFERS]; - volatile struct dbdma_cmd *last_cmd[MAX_GBUFFERS]; - volatile struct dbdma_cmd *pre_cmd[MAX_GBUFFERS]; - int need_pre_capture[MAX_GBUFFERS]; -#define PLANB_DUMMY 40 /* # of command buf's allocated for pre-capture seq. */ - int gwidth[MAX_GBUFFERS], gheight[MAX_GBUFFERS]; - unsigned int gfmt[MAX_GBUFFERS]; - int gnorm_switch[MAX_GBUFFERS]; - volatile unsigned int *frame_stat; -#define GBUFFER_UNUSED 0x00U -#define GBUFFER_GRABBING 0x01U -#define GBUFFER_DONE 0x02U -#ifdef PLANB_GSCANLINE - int gbytes_per_line; -#else -#define MAX_LNUM 431 /* change this if PLANB_MAXLINES or */ - /* PLANB_MAXPIXELS changes */ - int l_fr_addr_idx[MAX_GBUFFERS]; - unsigned char *l_to_addr[MAX_GBUFFERS][MAX_LNUM]; - int l_to_next_idx[MAX_GBUFFERS][MAX_LNUM]; - int l_to_next_size[MAX_GBUFFERS][MAX_LNUM]; - int lsize[MAX_GBUFFERS], lnum[MAX_GBUFFERS]; -#endif -}; - -#endif /* __KERNEL__ */ - -#endif /* _PLANB_H_ */ diff --git a/drivers/media/video/saa7196.h b/drivers/media/video/saa7196.h index cd4b6354a7b..e69de29bb2d 100644 --- a/drivers/media/video/saa7196.h +++ b/drivers/media/video/saa7196.h @@ -1,117 +0,0 @@ -/* - Definitions for the Philips SAA7196 digital video decoder, - scaler, and clock generator circuit (DESCpro), as used in - the PlanB video input of the Powermac 7x00/8x00 series. - - Copyright (C) 1998 Michel Lanners (mlan@cpu.lu) - - The register defines are shamelessly copied from the meteor - driver out of NetBSD (with permission), - and are copyrighted (c) 1995 Mark Tinguely and Jim Lowe - (Thanks !) - - Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.edu) - - The default values used for PlanB are my mistakes. -*/ - -/* $Id: saa7196.h,v 1.5 1999/03/26 23:28:47 mlan Exp $ */ - -#ifndef _SAA7196_H_ -#define _SAA7196_H_ - -#define SAA7196_NUMREGS 0x31 /* Number of registers (used)*/ -#define NUM_SUPPORTED_NORM 3 /* Number of supported norms by PlanB */ - -/* Decoder part: */ -#define SAA7196_IDEL 0x00 /* Increment delay */ -#define SAA7196_HSB5 0x01 /* H-sync begin; 50 hz */ -#define SAA7196_HSS5 0x02 /* H-sync stop; 50 hz */ -#define SAA7196_HCB5 0x03 /* H-clamp begin; 50 hz */ -#define SAA7196_HCS5 0x04 /* H-clamp stop; 50 hz */ -#define SAA7196_HSP5 0x05 /* H-sync after PHI1; 50 hz */ -#define SAA7196_LUMC 0x06 /* Luminance control */ -#define SAA7196_HUEC 0x07 /* Hue control */ -#define SAA7196_CKTQ 0x08 /* Colour Killer Threshold QAM (PAL, NTSC) */ -#define SAA7196_CKTS 0x09 /* Colour Killer Threshold SECAM */ -#define SAA7196_PALS 0x0a /* PAL switch sensitivity */ -#define SAA7196_SECAMS 0x0b /* SECAM switch sensitivity */ -#define SAA7196_CGAINC 0x0c /* Chroma gain control */ -#define SAA7196_STDC 0x0d /* Standard/Mode control */ -#define SAA7196_IOCC 0x0e /* I/O and Clock Control */ -#define SAA7196_CTRL1 0x0f /* Control #1 */ -#define SAA7196_CTRL2 0x10 /* Control #2 */ -#define SAA7196_CGAINR 0x11 /* Chroma Gain Reference */ -#define SAA7196_CSAT 0x12 /* Chroma Saturation */ -#define SAA7196_CONT 0x13 /* Luminance Contrast */ -#define SAA7196_HSB6 0x14 /* H-sync begin; 60 hz */ -#define SAA7196_HSS6 0x15 /* H-sync stop; 60 hz */ -#define SAA7196_HCB6 0x16 /* H-clamp begin; 60 hz */ -#define SAA7196_HCS6 0x17 /* H-clamp stop; 60 hz */ -#define SAA7196_HSP6 0x18 /* H-sync after PHI1; 60 hz */ -#define SAA7196_BRIG 0x19 /* Luminance Brightness */ - -/* Scaler part: */ -#define SAA7196_FMTS 0x20 /* Formats and sequence */ -#define SAA7196_OUTPIX 0x21 /* Output data pixel/line */ -#define SAA7196_INPIX 0x22 /* Input data pixel/line */ -#define SAA7196_HWS 0x23 /* Horiz. window start */ -#define SAA7196_HFILT 0x24 /* Horiz. filter */ -#define SAA7196_OUTLINE 0x25 /* Output data lines/field */ -#define SAA7196_INLINE 0x26 /* Input data lines/field */ -#define SAA7196_VWS 0x27 /* Vertical window start */ -#define SAA7196_VYP 0x28 /* AFS/vertical Y processing */ -#define SAA7196_VBS 0x29 /* Vertical Bypass start */ -#define SAA7196_VBCNT 0x2a /* Vertical Bypass count */ -#define SAA7196_VBP 0x2b /* veritcal Bypass Polarity */ -#define SAA7196_VLOW 0x2c /* Colour-keying lower V limit */ -#define SAA7196_VHIGH 0x2d /* Colour-keying upper V limit */ -#define SAA7196_ULOW 0x2e /* Colour-keying lower U limit */ -#define SAA7196_UHIGH 0x2f /* Colour-keying upper U limit */ -#define SAA7196_DPATH 0x30 /* Data path setting */ - -/* Initialization default values: */ - -unsigned char saa_regs[NUM_SUPPORTED_NORM][SAA7196_NUMREGS] = { - -/* PAL, 768x576 (no scaling), composite video-in */ -/* Decoder: */ - { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x63, 0xff, - 0xfe, 0xf0, 0xfe, 0xe0, 0x20, 0x06, 0x3b, 0x98, - 0x00, 0x59, 0x41, 0x45, 0x34, 0x0a, 0xf4, 0xd2, - 0xe9, 0xa2, -/* Padding */ - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* Scaler: */ - 0x72, 0x80, 0x00, 0x03, 0x8d, 0x20, 0x20, 0x12, - 0xa5, 0x12, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, - 0x87 }, - -/* NTSC, 640x480? (no scaling), composite video-in */ -/* Decoder: */ - { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x50, 0x00, - 0xf8, 0xf0, 0xfe, 0xe0, 0x00, 0x06, 0x3b, 0x98, - 0x00, 0x2c, 0x3d, 0x40, 0x34, 0x0a, 0xf4, 0xd2, - 0xe9, 0x98, -/* Padding */ - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* Scaler: */ - 0x72, 0x80, 0x80, 0x03, 0x89, 0xf0, 0xf0, 0x0d, - 0xa0, 0x0d, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, - 0x87 }, - -/* SECAM, 768x576 (no scaling), composite video-in */ -/* Decoder: */ - { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x63, 0xff, - 0xfe, 0xf0, 0xfe, 0xe0, 0x20, 0x07, 0x3b, 0x98, - 0x00, 0x59, 0x41, 0x45, 0x34, 0x0a, 0xf4, 0xd2, - 0xe9, 0xa2, -/* Padding */ - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* Scaler: */ - 0x72, 0x80, 0x00, 0x03, 0x8d, 0x20, 0x20, 0x12, - 0xa5, 0x12, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, - 0x87 } - }; - -#endif /* _SAA7196_H_ */ -- cgit v1.2.3 From 33b687cf1df62bd83167616516922b4e472be662 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 25 Jul 2008 05:32:50 -0300 Subject: V4L/DVB (8487): videodev: replace videodev.h includes by videodev2.h where possible Several V4L2 drivers still included videodev.h. Fix this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cs53l32a.c | 2 +- drivers/media/video/m52790.c | 2 +- drivers/media/video/msp3400-driver.c | 1 - drivers/media/video/msp3400-kthreads.c | 1 - drivers/media/video/saa717x.c | 1 - drivers/media/video/tda7432.c | 2 +- drivers/media/video/tda9875.c | 2 +- drivers/media/video/tlv320aic23b.c | 2 +- drivers/media/video/tveeprom.c | 2 +- drivers/media/video/tvp5150.c | 2 +- drivers/media/video/v4l2-common.c | 2 +- drivers/media/video/vino.c | 2 +- drivers/media/video/vp27smpx.c | 2 +- drivers/media/video/vpx3220.c | 2 +- drivers/media/video/w9966.c | 2 +- drivers/media/video/w9968cf.h | 2 +- drivers/media/video/wm8739.c | 2 +- drivers/media/video/wm8775.c | 2 +- 18 files changed, 15 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index 645b339152d..e30a589c0e1 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c index 39bf6b114d5..89a781c6929 100644 --- a/drivers/media/video/m52790.c +++ b/drivers/media/video/m52790.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index 780531b587a..3da74dcee90 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -51,7 +51,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c index 1622f70e4dd..846a14a61fd 100644 --- a/drivers/media/video/msp3400-kthreads.c +++ b/drivers/media/video/msp3400-kthreads.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c index 2220f956994..af60ede5310 100644 --- a/drivers/media/video/saa717x.c +++ b/drivers/media/video/saa717x.c @@ -35,7 +35,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index 2fda40c0f25..4963d426488 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index 7a8ce8fb46d..792f0b07990 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c index 9220378a563..281065b9dd2 100644 --- a/drivers/media/video/tlv320aic23b.c +++ b/drivers/media/video/tlv320aic23b.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index fbfac1b3bd0..bcc32fa92a8 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index 6a3af1005f0..28af5ce5560 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -6,7 +6,7 @@ */ #include -#include +#include #include #include #include diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index e9dd996fd5d..88ca1310441 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -64,7 +64,7 @@ #include #endif -#include +#include MODULE_AUTHOR("Bill Dirks, Justin Schoeman, Gerd Knorr"); MODULE_DESCRIPTION("misc helper functions for v4l2 device drivers"); diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index 01ea99c9bc1..f0fcb008b72 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -38,7 +38,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index cbecb3cbbba..577956c5410 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c index 35293029da0..3b83d4e2b2c 100644 --- a/drivers/media/video/vpx3220.c +++ b/drivers/media/video/vpx3220.c @@ -33,7 +33,7 @@ #define I2C_NAME(x) (x)->name -#include +#include #include #include diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c index 1641998c73e..925b4e7b557 100644 --- a/drivers/media/video/w9966.c +++ b/drivers/media/video/w9966.c @@ -57,7 +57,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/video/w9968cf.h b/drivers/media/video/w9968cf.h index 3c95316bc03..30032e15e23 100644 --- a/drivers/media/video/w9968cf.h +++ b/drivers/media/video/w9968cf.h @@ -21,7 +21,7 @@ #ifndef _W9968CF_H_ #define _W9968CF_H_ -#include +#include #include #include #include diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c index 7be47a25585..95c79ad8048 100644 --- a/drivers/media/video/wm8739.c +++ b/drivers/media/video/wm8739.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index c2ab70a04a7..48df661d4fc 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3 From f894dfd735237548d282d6fd55b6ebb4b2fd9ef2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 25 Jul 2008 07:39:54 -0300 Subject: V4L/DVB (8488): videodev: remove some CONFIG_VIDEO_V4L1_COMPAT code from v4l2-dev.h The video_device_create_file and video_device_remove_file functions can be removed from v4l2-dev.h, removing the dependency on videodev.h in v4l2-dev.h. Also removed a few more videodev.h includes that should have been videodev2.h. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/tda9887.c | 2 +- drivers/media/common/tuners/tuner-simple.c | 2 +- drivers/media/video/cpia2/cpia2_core.c | 1 + drivers/media/video/ov511.c | 34 +++++++++--------- drivers/media/video/pwc/pwc-if.c | 11 +++--- drivers/media/video/stk-webcam.c | 14 ++++---- drivers/media/video/stv680.c | 47 +++++++++++++------------ drivers/media/video/usbvideo/vicam.c | 1 + drivers/media/video/usbvision/usbvision-core.c | 1 - drivers/media/video/usbvision/usbvision-video.c | 1 - drivers/media/video/vpx3220.c | 2 +- 11 files changed, 60 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/tda9887.c b/drivers/media/common/tuners/tda9887.c index a0545ba957b..72abf0b7348 100644 --- a/drivers/media/common/tuners/tda9887.c +++ b/drivers/media/common/tuners/tda9887.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include "tuner-i2c.h" diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c index 266c255cf0d..597e47f5d69 100644 --- a/drivers/media/common/tuners/tuner-simple.c +++ b/drivers/media/common/tuners/tuner-simple.c @@ -6,7 +6,7 @@ */ #include #include -#include +#include #include #include #include diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c index f2e8b1c82c6..af8b9ec8e35 100644 --- a/drivers/media/video/cpia2/cpia2_core.c +++ b/drivers/media/video/cpia2/cpia2_core.c @@ -32,6 +32,7 @@ #include "cpia2.h" #include +#include #include #include diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index f732b035570..2374ebc084d 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c @@ -5660,43 +5660,43 @@ static int ov_create_sysfs(struct video_device *vdev) { int rc; - rc = video_device_create_file(vdev, &dev_attr_custom_id); + rc = device_create_file(&vdev->dev, &dev_attr_custom_id); if (rc) goto err; - rc = video_device_create_file(vdev, &dev_attr_model); + rc = device_create_file(&vdev->dev, &dev_attr_model); if (rc) goto err_id; - rc = video_device_create_file(vdev, &dev_attr_bridge); + rc = device_create_file(&vdev->dev, &dev_attr_bridge); if (rc) goto err_model; - rc = video_device_create_file(vdev, &dev_attr_sensor); + rc = device_create_file(&vdev->dev, &dev_attr_sensor); if (rc) goto err_bridge; - rc = video_device_create_file(vdev, &dev_attr_brightness); + rc = device_create_file(&vdev->dev, &dev_attr_brightness); if (rc) goto err_sensor; - rc = video_device_create_file(vdev, &dev_attr_saturation); + rc = device_create_file(&vdev->dev, &dev_attr_saturation); if (rc) goto err_bright; - rc = video_device_create_file(vdev, &dev_attr_contrast); + rc = device_create_file(&vdev->dev, &dev_attr_contrast); if (rc) goto err_sat; - rc = video_device_create_file(vdev, &dev_attr_hue); + rc = device_create_file(&vdev->dev, &dev_attr_hue); if (rc) goto err_contrast; - rc = video_device_create_file(vdev, &dev_attr_exposure); + rc = device_create_file(&vdev->dev, &dev_attr_exposure); if (rc) goto err_hue; return 0; err_hue: - video_device_remove_file(vdev, &dev_attr_hue); + device_remove_file(&vdev->dev, &dev_attr_hue); err_contrast: - video_device_remove_file(vdev, &dev_attr_contrast); + device_remove_file(&vdev->dev, &dev_attr_contrast); err_sat: - video_device_remove_file(vdev, &dev_attr_saturation); + device_remove_file(&vdev->dev, &dev_attr_saturation); err_bright: - video_device_remove_file(vdev, &dev_attr_brightness); + device_remove_file(&vdev->dev, &dev_attr_brightness); err_sensor: - video_device_remove_file(vdev, &dev_attr_sensor); + device_remove_file(&vdev->dev, &dev_attr_sensor); err_bridge: - video_device_remove_file(vdev, &dev_attr_bridge); + device_remove_file(&vdev->dev, &dev_attr_bridge); err_model: - video_device_remove_file(vdev, &dev_attr_model); + device_remove_file(&vdev->dev, &dev_attr_model); err_id: - video_device_remove_file(vdev, &dev_attr_custom_id); + device_remove_file(&vdev->dev, &dev_attr_custom_id); err: return rc; } diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 4625b265bf9..436a47caf52 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -1047,19 +1047,20 @@ static int pwc_create_sysfs_files(struct video_device *vdev) struct pwc_device *pdev = video_get_drvdata(vdev); int rc; - rc = video_device_create_file(vdev, &dev_attr_button); + rc = device_create_file(&vdev->dev, &dev_attr_button); if (rc) goto err; if (pdev->features & FEATURE_MOTOR_PANTILT) { - rc = video_device_create_file(vdev, &dev_attr_pan_tilt); + rc = device_create_file(&vdev->dev, &dev_attr_pan_tilt); if (rc) goto err_button; } return 0; err_button: - video_device_remove_file(vdev, &dev_attr_button); + device_remove_file(&vdev->dev, &dev_attr_button); err: + PWC_ERROR("Could not create sysfs files.\n"); return rc; } @@ -1067,8 +1068,8 @@ static void pwc_remove_sysfs_files(struct video_device *vdev) { struct pwc_device *pdev = video_get_drvdata(vdev); if (pdev->features & FEATURE_MOTOR_PANTILT) - video_device_remove_file(vdev, &dev_attr_pan_tilt); - video_device_remove_file(vdev, &dev_attr_button); + device_remove_file(&vdev->dev, &dev_attr_pan_tilt); + device_remove_file(&vdev->dev, &dev_attr_button); } #ifdef CONFIG_USB_PWC_DEBUG diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index 8d5fa95ad95..8aa56fe0254 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -341,17 +341,19 @@ static int stk_create_sysfs_files(struct video_device *vdev) { int ret; - ret = video_device_create_file(vdev, &dev_attr_brightness); - ret += video_device_create_file(vdev, &dev_attr_hflip); - ret += video_device_create_file(vdev, &dev_attr_vflip); + ret = device_create_file(&vdev->dev, &dev_attr_brightness); + ret += device_create_file(&vdev->dev, &dev_attr_hflip); + ret += device_create_file(&vdev->dev, &dev_attr_vflip); + if (ret) + STK_WARNING("Could not create sysfs files\n"); return ret; } static void stk_remove_sysfs_files(struct video_device *vdev) { - video_device_remove_file(vdev, &dev_attr_brightness); - video_device_remove_file(vdev, &dev_attr_hflip); - video_device_remove_file(vdev, &dev_attr_vflip); + device_remove_file(&vdev->dev, &dev_attr_brightness); + device_remove_file(&vdev->dev, &dev_attr_hflip); + device_remove_file(&vdev->dev, &dev_attr_vflip); } #else diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index fdcb58b0c12..9053d5a0b1c 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -525,53 +525,54 @@ static int stv680_create_sysfs_files(struct video_device *vdev) { int rc; - rc = video_device_create_file(vdev, &dev_attr_model); + rc = device_create_file(&vdev->dev, &dev_attr_model); if (rc) goto err; - rc = video_device_create_file(vdev, &dev_attr_in_use); + rc = device_create_file(&vdev->dev, &dev_attr_in_use); if (rc) goto err_model; - rc = video_device_create_file(vdev, &dev_attr_streaming); + rc = device_create_file(&vdev->dev, &dev_attr_streaming); if (rc) goto err_inuse; - rc = video_device_create_file(vdev, &dev_attr_palette); + rc = device_create_file(&vdev->dev, &dev_attr_palette); if (rc) goto err_stream; - rc = video_device_create_file(vdev, &dev_attr_frames_total); + rc = device_create_file(&vdev->dev, &dev_attr_frames_total); if (rc) goto err_pal; - rc = video_device_create_file(vdev, &dev_attr_frames_read); + rc = device_create_file(&vdev->dev, &dev_attr_frames_read); if (rc) goto err_framtot; - rc = video_device_create_file(vdev, &dev_attr_packets_dropped); + rc = device_create_file(&vdev->dev, &dev_attr_packets_dropped); if (rc) goto err_framread; - rc = video_device_create_file(vdev, &dev_attr_decoding_errors); + rc = device_create_file(&vdev->dev, &dev_attr_decoding_errors); if (rc) goto err_dropped; return 0; err_dropped: - video_device_remove_file(vdev, &dev_attr_packets_dropped); + device_remove_file(&vdev->dev, &dev_attr_packets_dropped); err_framread: - video_device_remove_file(vdev, &dev_attr_frames_read); + device_remove_file(&vdev->dev, &dev_attr_frames_read); err_framtot: - video_device_remove_file(vdev, &dev_attr_frames_total); + device_remove_file(&vdev->dev, &dev_attr_frames_total); err_pal: - video_device_remove_file(vdev, &dev_attr_palette); + device_remove_file(&vdev->dev, &dev_attr_palette); err_stream: - video_device_remove_file(vdev, &dev_attr_streaming); + device_remove_file(&vdev->dev, &dev_attr_streaming); err_inuse: - video_device_remove_file(vdev, &dev_attr_in_use); + device_remove_file(&vdev->dev, &dev_attr_in_use); err_model: - video_device_remove_file(vdev, &dev_attr_model); + device_remove_file(&vdev->dev, &dev_attr_model); err: + PDEBUG(0, "STV(e): Could not create sysfs files"); return rc; } static void stv680_remove_sysfs_files(struct video_device *vdev) { - video_device_remove_file(vdev, &dev_attr_model); - video_device_remove_file(vdev, &dev_attr_in_use); - video_device_remove_file(vdev, &dev_attr_streaming); - video_device_remove_file(vdev, &dev_attr_palette); - video_device_remove_file(vdev, &dev_attr_frames_total); - video_device_remove_file(vdev, &dev_attr_frames_read); - video_device_remove_file(vdev, &dev_attr_packets_dropped); - video_device_remove_file(vdev, &dev_attr_decoding_errors); + device_remove_file(&vdev->dev, &dev_attr_model); + device_remove_file(&vdev->dev, &dev_attr_in_use); + device_remove_file(&vdev->dev, &dev_attr_streaming); + device_remove_file(&vdev->dev, &dev_attr_palette); + device_remove_file(&vdev->dev, &dev_attr_frames_total); + device_remove_file(&vdev->dev, &dev_attr_frames_read); + device_remove_file(&vdev->dev, &dev_attr_packets_dropped); + device_remove_file(&vdev->dev, &dev_attr_decoding_errors); } /******************************************************************** diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c index e2dec6fb0da..b8e8fceee52 100644 --- a/drivers/media/video/usbvideo/vicam.c +++ b/drivers/media/video/usbvideo/vicam.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 7d53de531c4..c317ed7a848 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index e97f955aad6..a65e5db0a32 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -53,7 +53,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c index 3b83d4e2b2c..35293029da0 100644 --- a/drivers/media/video/vpx3220.c +++ b/drivers/media/video/vpx3220.c @@ -33,7 +33,7 @@ #define I2C_NAME(x) (x)->name -#include +#include #include #include -- cgit v1.2.3 From 655b8408557d586212d0797d423babdc464c587f Mon Sep 17 00:00:00 2001 From: reinhard schwab Date: Sat, 26 Jul 2008 10:47:00 -0300 Subject: V4L/DVB (8489): add dvb-t support for terratec cinergy hybrid T usb xs This patch adds dvbt support for the terratec cinergy hybrid T usb xsstick. Thanks to Devin Heitmueller and Mauro Chehab for guiding me. Signed-off-by: Reinhard Schwab Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 4 ++++ drivers/media/video/em28xx/em28xx-dvb.c | 9 +++++++++ 2 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 6e0eb950ab8..edf6f77862c 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -246,6 +246,7 @@ struct em28xx_board em28xx_boards[] = { .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, .decoder = EM28XX_TVP5150, + .has_dvb = 1, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, @@ -639,6 +640,9 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: ctl->demod = XC3028_FE_ZARLINK456; break; + case EM2880_BOARD_TERRATEC_HYBRID_XS: + ctl->demod = XC3028_FE_ZARLINK456; + break; case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: /* djh - Not sure which demod we need here */ ctl->demod = XC3028_FE_DEFAULT; diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index cc61cfb23a4..9727653b76f 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -441,6 +441,15 @@ static int dvb_init(struct em28xx *dev) } break; #endif + case EM2880_BOARD_TERRATEC_HYBRID_XS: + dvb->frontend = dvb_attach(zl10353_attach, + &em28xx_zl10353_with_xc3028, + &dev->i2c_adap); + if (attach_xc3028(0x61, dev) < 0) { + result = -EINVAL; + goto out_free; + } + break; default: printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card" " isn't supported yet\n", -- cgit v1.2.3 From f78d92c9ffcda7451b5943ab491c087f1ec7e08d Mon Sep 17 00:00:00 2001 From: Dean Anderson Date: Tue, 22 Jul 2008 14:43:27 -0300 Subject: V4L/DVB (8490): s2255drv Sensoray 2255 driver fixes This patch fixes timer issues in driver disconnect. It also removes the restriction of one user per channel at a time. Thanks to Oliver Neukum and Mauro Chehab for finding these issues. Locking of video stream partly based on saa7134 driver. Signed-off-by: Dean Anderson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s2255drv.c | 111 ++++++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c index 2428d441fe1..9ff5403483e 100644 --- a/drivers/media/video/s2255drv.c +++ b/drivers/media/video/s2255drv.c @@ -185,6 +185,7 @@ struct s2255_dmaqueue { #define S2255_FW_LOADED_DSPWAIT 1 #define S2255_FW_SUCCESS 2 #define S2255_FW_FAILED 3 +#define S2255_FW_DISCONNECTING 4 struct s2255_fw { int fw_loaded; @@ -264,7 +265,6 @@ struct s2255_buffer { struct s2255_fh { struct s2255_dev *dev; - unsigned int resources; const struct s2255_fmt *fmt; unsigned int width; unsigned int height; @@ -274,14 +274,9 @@ struct s2255_fh { /* mode below is the desired mode. mode in s2255_dev is the current mode that was last set */ struct s2255_mode mode; + int resources[MAX_CHANNELS]; }; -/* - * TODO: fixme S2255_MAX_USERS. Do not limit open driver handles. - * Limit V4L to one stream at a time. - */ -#define S2255_MAX_USERS 1 - #define CUR_USB_FWVER 774 /* current cypress EEPROM firmware version */ #define S2255_MAJOR_VERSION 1 #define S2255_MINOR_VERSION 13 @@ -477,10 +472,9 @@ static void s2255_timer(unsigned long user_data) dprintk(100, "s2255 timer\n"); if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { printk(KERN_ERR "s2255: can't submit urb\n"); - if (data->fw) { - release_firmware(data->fw); - data->fw = NULL; - } + atomic_set(&data->fw_state, S2255_FW_FAILED); + /* wake up anything waiting for the firmware */ + wake_up(&data->wait_fw); return; } } @@ -510,13 +504,18 @@ static void s2255_fwchunk_complete(struct urb *urb) struct usb_device *udev = urb->dev; int len; dprintk(100, "udev %p urb %p", udev, urb); - /* TODO: fixme. reflect change in status */ if (urb->status) { dev_err(&udev->dev, "URB failed with status %d", urb->status); + atomic_set(&data->fw_state, S2255_FW_FAILED); + /* wake up anything waiting for the firmware */ + wake_up(&data->wait_fw); return; } if (data->fw_urb == NULL) { - dev_err(&udev->dev, "early disconncect\n"); + dev_err(&udev->dev, "s2255 disconnected\n"); + atomic_set(&data->fw_state, S2255_FW_FAILED); + /* wake up anything waiting for the firmware */ + wake_up(&data->wait_fw); return; } #define CHUNK_SIZE 512 @@ -790,7 +789,8 @@ static int res_get(struct s2255_dev *dev, struct s2255_fh *fh) } /* it's free, grab it */ dev->resources[fh->channel] = 1; - dprintk(1, "res: get\n"); + fh->resources[fh->channel] = 1; + dprintk(1, "s2255: res: get\n"); mutex_unlock(&dev->lock); return 1; } @@ -800,9 +800,18 @@ static int res_locked(struct s2255_dev *dev, struct s2255_fh *fh) return dev->resources[fh->channel]; } +static int res_check(struct s2255_fh *fh) +{ + return fh->resources[fh->channel]; +} + + static void res_free(struct s2255_dev *dev, struct s2255_fh *fh) { + mutex_lock(&dev->lock); dev->resources[fh->channel] = 0; + fh->resources[fh->channel] = 0; + mutex_unlock(&dev->lock); dprintk(1, "res: put\n"); } @@ -1233,7 +1242,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) } if (!res_get(dev, fh)) { - dev_err(&dev->udev->dev, "res get busy\n"); + dev_err(&dev->udev->dev, "s2255: stream busy\n"); return -EBUSY; } @@ -1289,8 +1298,10 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) } s2255_stop_acquire(dev, fh->channel); res = videobuf_streamoff(&fh->vb_vidq); + if (res < 0) + return res; res_free(dev, fh); - return res; + return 0; } static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) @@ -1463,12 +1474,7 @@ static int s2255_open(struct inode *inode, struct file *file) mutex_lock(&dev->open_lock); dev->users[cur_channel]++; - if (dev->users[cur_channel] > S2255_MAX_USERS) { - dev->users[cur_channel]--; - mutex_unlock(&dev->open_lock); - printk(KERN_INFO "s2255drv: too many open handles!\n"); - return -EBUSY; - } + dprintk(4, "s2255: open_handles %d\n", dev->users[cur_channel]); if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_FAILED) { err("2255 firmware load failed. retrying.\n"); @@ -1479,7 +1485,8 @@ static int s2255_open(struct inode *inode, struct file *file) msecs_to_jiffies(S2255_LOAD_TIMEOUT)); if (atomic_read(&dev->fw_data->fw_state) != S2255_FW_SUCCESS) { - printk(KERN_INFO "2255 FW load failed after 2 tries\n"); + printk(KERN_INFO "2255 FW load failed.\n"); + dev->users[cur_channel]--; mutex_unlock(&dev->open_lock); return -EFAULT; } @@ -1495,6 +1502,7 @@ static int s2255_open(struct inode *inode, struct file *file) != S2255_FW_SUCCESS) { printk(KERN_INFO "2255 firmware not loaded" "try again\n"); + dev->users[cur_channel]--; mutex_unlock(&dev->open_lock); return -EBUSY; } @@ -1503,6 +1511,7 @@ static int s2255_open(struct inode *inode, struct file *file) /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh), GFP_KERNEL); if (NULL == fh) { + dev->users[cur_channel]--; mutex_unlock(&dev->open_lock); return -ENOMEM; } @@ -1562,44 +1571,48 @@ static void s2255_destroy(struct kref *kref) printk(KERN_ERR "s2255drv: kref problem\n"); return; } + + /* + * Wake up any firmware load waiting (only done in .open, + * which holds the open_lock mutex) + */ + atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING); + wake_up(&dev->fw_data->wait_fw); + /* prevent s2255_disconnect from racing s2255_open */ mutex_lock(&dev->open_lock); s2255_exit_v4l(dev); - /* device unregistered so no longer possible to open. open_mutex - can be unlocked */ + /* + * device unregistered so no longer possible to open. open_mutex + * can be unlocked and timers deleted afterwards. + */ mutex_unlock(&dev->open_lock); /* board shutdown stops the read pipe if it is running */ s2255_board_shutdown(dev); /* make sure firmware still not trying to load */ + del_timer(&dev->timer); /* only started in .probe and .open */ + if (dev->fw_data->fw_urb) { dprintk(2, "kill fw_urb\n"); usb_kill_urb(dev->fw_data->fw_urb); usb_free_urb(dev->fw_data->fw_urb); dev->fw_data->fw_urb = NULL; } + /* - * TODO: fixme(above, below): potentially leaving timers alive. - * do not ignore timeout below if - * it occurs. + * delete the dsp_wait timer, which sets the firmware + * state on completion. This is done before fw_data + * is freed below. */ - /* make sure we aren't waiting for the DSP */ - if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_LOADED_DSPWAIT) { - /* if we are, wait for the wakeup for fw_success or timeout */ - wait_event_timeout(dev->fw_data->wait_fw, - (atomic_read(&dev->fw_data->fw_state) - == S2255_FW_SUCCESS), - msecs_to_jiffies(S2255_LOAD_TIMEOUT)); - } + del_timer(&dev->fw_data->dsp_wait); /* only started in .open */ - if (dev->fw_data) { - if (dev->fw_data->fw) - release_firmware(dev->fw_data->fw); - kfree(dev->fw_data->pfw_data); - kfree(dev->fw_data); - } + if (dev->fw_data->fw) + release_firmware(dev->fw_data->fw); + kfree(dev->fw_data->pfw_data); + kfree(dev->fw_data); usb_put_dev(dev->udev); dprintk(1, "%s", __func__); @@ -1616,17 +1629,23 @@ static int s2255_close(struct inode *inode, struct file *file) mutex_lock(&dev->open_lock); - if (dev->b_acquire[fh->channel]) - s2255_stop_acquire(dev, fh->channel); - res_free(dev, fh); + /* turn off stream */ + if (res_check(fh)) { + if (dev->b_acquire[fh->channel]) + s2255_stop_acquire(dev, fh->channel); + videobuf_streamoff(&fh->vb_vidq); + res_free(dev, fh); + } + videobuf_mmap_free(&fh->vb_vidq); - kfree(fh); dev->users[fh->channel]--; + mutex_unlock(&dev->open_lock); kref_put(&dev->kref, s2255_destroy); dprintk(1, "s2255: close called (minor=%d, users=%d)\n", minor, dev->users[fh->channel]); + kfree(fh); return 0; } -- cgit v1.2.3 From b18559076a31ab0be2d980ce2beff8e32504e080 Mon Sep 17 00:00:00 2001 From: Jaime Velasco Juan Date: Tue, 22 Jul 2008 12:28:36 -0300 Subject: V4L/DVB (8491): stkwebcam: Always reuse last queued buffer This change keeps the video stream going on when the application is slow queuing buffers, instead of spamming dmesg and hanging. Fixes a problem with aMSN reported by Samed Beyribey Signed-off-by: Jaime Velasco Juan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/stk-webcam.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index 8aa56fe0254..a8a72768ca9 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -445,18 +445,19 @@ static void stk_isoc_handler(struct urb *urb) fb->v4lbuf.bytesused = 0; fill = fb->buffer; } else if (fb->v4lbuf.bytesused == dev->frame_size) { - list_move_tail(dev->sio_avail.next, - &dev->sio_full); - wake_up(&dev->wait_frame); - if (list_empty(&dev->sio_avail)) { - (void) (printk_ratelimit() && - STK_ERROR("No buffer available\n")); - goto resubmit; + if (list_is_singular(&dev->sio_avail)) { + /* Always reuse the last buffer */ + fb->v4lbuf.bytesused = 0; + fill = fb->buffer; + } else { + list_move_tail(dev->sio_avail.next, + &dev->sio_full); + wake_up(&dev->wait_frame); + fb = list_first_entry(&dev->sio_avail, + struct stk_sio_buffer, list); + fb->v4lbuf.bytesused = 0; + fill = fb->buffer; } - fb = list_first_entry(&dev->sio_avail, - struct stk_sio_buffer, list); - fb->v4lbuf.bytesused = 0; - fill = fb->buffer; } } else { framelen -= 4; -- cgit v1.2.3 From e14b3658a7651ffd9b1f407eaf07f4dde17ef1e7 Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Sat, 26 Jul 2008 11:04:33 -0300 Subject: V4L/DVB (8492): Add support for the ATI TV Wonder HD 600 em28xx-cards.c em28xx-dvb.c em28xx.h - Add support for the ATI TV Wonder HD 600, based on a 94 email exchange and USB traces provided by Ronnie Bailey Thanks to Ronnie Bailey for testing the changes Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 50 +++++++++++++++++++++++++++++++ drivers/media/video/em28xx/em28xx-dvb.c | 2 ++ drivers/media/video/em28xx/em28xx.h | 1 + 3 files changed, 53 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index edf6f77862c..81f9ff55588 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -240,6 +240,52 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, + [EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = { + .name = "AMD ATI TV Wonder HD 600", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .mts_firmware = 1, + .has_12mhz_i2s = 1, + .has_dvb = 1, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = { + .name = "AMD ATI TV Wonder HD 600", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .mts_firmware = 1, + .has_12mhz_i2s = 1, + .has_dvb = 1, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, [EM2880_BOARD_TERRATEC_HYBRID_XS] = { .name = "Terratec Hybrid XS", .vchannels = 3, @@ -493,6 +539,8 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS }, { USB_DEVICE(0x0ccd, 0x0047), .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, + { USB_DEVICE(0x0438, 0xb002), + .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, { }, }; MODULE_DEVICE_TABLE(usb, em28xx_id_table); @@ -608,6 +656,7 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2880_BOARD_TERRATEC_HYBRID_XS: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: + case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); msleep(50); @@ -649,6 +698,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) break; case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: + case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: /* FIXME: Better to specify the needed IF */ ctl->demod = XC3028_FE_DEFAULT; break; diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index 9727653b76f..31475a24571 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -6,6 +6,7 @@ (c) 2008 Devin Heitmueller - Fixes for the driver to properly work with HVR-950 - Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick + - Fixes for the driver to properly work with AMD ATI TV Wonder HD 600 (c) 2008 Aidan Thornton @@ -411,6 +412,7 @@ static int dvb_init(struct em28xx *dev) switch (dev->model) { case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: + case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: dvb->frontend = dvb_attach(lgdt330x_attach, &em2880_lgdt3303_dev, &dev->i2c_adap); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 89842c5d64a..9da877375cf 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -58,6 +58,7 @@ #define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17 #define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18 #define EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA 19 +#define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 20 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 -- cgit v1.2.3 From 1ffdddd6fa3d18982133f6d149d456312d8bfcac Mon Sep 17 00:00:00 2001 From: roel kluin Date: Mon, 21 Jul 2008 21:29:46 -0300 Subject: V4L/DVB (8493): mt20xx: test below 0 on unsigned lo1a and lo2a lo1a and lo2a are unsigned ints so these tests won't work. Signed-off-by: Roel Kluin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/mt20xx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/mt20xx.c b/drivers/media/common/tuners/mt20xx.c index fbcb2823373..35b763a16d5 100644 --- a/drivers/media/common/tuners/mt20xx.c +++ b/drivers/media/common/tuners/mt20xx.c @@ -148,7 +148,8 @@ static int mt2032_compute_freq(struct dvb_frontend *fe, tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n", rfin,lo2,lo2n,lo2a,lo2num,lo2freq); - if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) { + if (lo1a > 7 || lo1n < 17 || lo1n > 48 || lo2a > 7 || lo2n < 17 || + lo2n > 30) { tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n", lo1a, lo1n, lo2a,lo2n); return(-1); -- cgit v1.2.3 From fe0d3dff464bdd0cfe56829d86e358438647046c Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 21 Jul 2008 16:33:48 -0300 Subject: V4L/DVB (8494): make cx25840_debug static cx25840_debug can now become static. Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 2 +- drivers/media/video/cx25840/cx25840-core.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index e7bf4f4c131..209d3bcb5db 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -50,7 +50,7 @@ MODULE_LICENSE("GPL"); static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END }; -int cx25840_debug; +static int cx25840_debug; module_param_named(debug,cx25840_debug, int, 0644); diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index 72916ba975a..b87337e590b 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h @@ -24,8 +24,6 @@ #include #include -extern int cx25840_debug; - /* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is present in Hauppauge PVR-150 (and possibly PVR-500) cards that have certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The -- cgit v1.2.3 From 53faa1b1b9a262a634d7761ab5c62bbb017666bd Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 21 Jul 2008 16:33:42 -0300 Subject: V4L/DVB (8495): usb/anysee.c: make struct anysee_usb_mutex static This patch makes the needlessly global struct anysee_usb_mutex static. Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/anysee.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index adfd4fc82ef..2f408d2e1ef 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -43,7 +43,7 @@ module_param_named(debug, dvb_usb_anysee_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -struct mutex anysee_usb_mutex; +static struct mutex anysee_usb_mutex; static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, u8 *rbuf, u8 rlen) -- cgit v1.2.3 From d53687d1d22c3204394658a31654de2f1efb0e8f Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Sat, 26 Jul 2008 11:30:03 -0300 Subject: V4L/DVB (8496): saa7134: Copy tuner data earlier in init to avoid overwriting manual tuner type When saa7134_board_init2 runs, it immediately overwrites the current value (set earlier from module parameter) of tuner_type with the static values, and then does autodetection. This patch moves the tuner_addr copy to earlier in saa7134_initdev and removes the tuner_type copy from saa7134_board_init2. Autodetection could still potentially change to the wrong tuner type, but it is now possible to override the default type for the card again. My card's tuner is configured with autodetection from eeprom, so I don't need to manually set the tuner. I've checked that the autodetection still works for my card. Signed-off-by: Simon Arlott Reviewed-by: Hermann Pitton Cc: Brian Marete Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 3 --- drivers/media/video/saa7134/saa7134-core.c | 5 +++-- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 6893f998d29..98364d171de 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -5853,9 +5853,6 @@ int saa7134_board_init2(struct saa7134_dev *dev) unsigned char buf; int board; - dev->tuner_type = saa7134_boards[dev->board].tuner_type; - dev->tuner_addr = saa7134_boards[dev->board].tuner_addr; - switch (dev->board) { case SAA7134_BOARD_BMK_MPEX_NOTUNER: case SAA7134_BOARD_BMK_MPEX_TUNER: diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index f3e7a598e4b..a404368308a 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -945,11 +945,12 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, dev->board = SAA7134_BOARD_UNKNOWN; } dev->autodetected = card[dev->nr] != dev->board; - dev->tuner_type = saa7134_boards[dev->board].tuner_type; + dev->tuner_type = saa7134_boards[dev->board].tuner_type; + dev->tuner_addr = saa7134_boards[dev->board].tuner_addr; dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf; if (UNSET != tuner[dev->nr]) dev->tuner_type = tuner[dev->nr]; - printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", dev->name,pci_dev->subsystem_vendor, pci_dev->subsystem_device,saa7134_boards[dev->board].name, dev->board, dev->autodetected ? -- cgit v1.2.3 From 90ac5ea37f91e38d798c5e355232ce7f9c2a24d4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 26 Jul 2008 11:42:29 -0300 Subject: V4L/DVB (8497): uvcvideo: Make the auto-exposure menu control V4L2 compliant V4L2 and UVC enumerate the auto-exposure settings in a different order. This patch fixes the auto-exposure menu declaration to match the V4L2 spec. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/uvc/uvc_ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index 3ae95512666..f54d06a8af9 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c @@ -195,8 +195,8 @@ static struct uvc_menu_info power_line_frequency_controls[] = { }; static struct uvc_menu_info exposure_auto_controls[] = { - { 1, "Manual Mode" }, { 2, "Auto Mode" }, + { 1, "Manual Mode" }, { 4, "Shutter Priority Mode" }, { 8, "Aperture Priority Mode" }, }; -- cgit v1.2.3 From 54812c77bc830e2dbcb62b4c6d8a9c7f97cfdd1b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 17 Jul 2008 07:37:37 -0300 Subject: V4L/DVB (8498): uvcvideo: Return sensible min and max values when querying a boolean control. Although the V4L2 spec states that the minimum and maximum fields may not be valid for control types other than V4L2_CTRL_TYPE_INTEGER, it makes sense to set the bounds to 0 and 1 for boolean controls instead of returning uninitialized values. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/uvc/uvc_ctrl.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index f54d06a8af9..626f4ad7e87 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c @@ -592,6 +592,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, if (ctrl == NULL) return -EINVAL; + memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl); v4l2_ctrl->id = mapping->id; v4l2_ctrl->type = mapping->v4l2_type; strncpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name); @@ -608,7 +609,8 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, v4l2_ctrl->default_value = uvc_get_le_value(data, mapping); } - if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) { + switch (mapping->v4l2_type) { + case V4L2_CTRL_TYPE_MENU: v4l2_ctrl->minimum = 0; v4l2_ctrl->maximum = mapping->menu_count - 1; v4l2_ctrl->step = 1; @@ -622,6 +624,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, } return 0; + + case V4L2_CTRL_TYPE_BOOLEAN: + v4l2_ctrl->minimum = 0; + v4l2_ctrl->maximum = 1; + v4l2_ctrl->step = 1; + return 0; + + default: + break; } if (ctrl->info->flags & UVC_CONTROL_GET_MIN) { -- cgit v1.2.3 From 85b9b8a444413ea5706096df13012520ed6c5103 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 14 Jul 2008 09:51:03 -0300 Subject: V4L/DVB (8499): zr36067: Rework device memory allocation Allocate zoran devices dynamically. Currently, the zr36067 driver stores the device structures in a global array, with room for 4 devices. This makes the bss section very large (90 kB!), and given that most users, I suspect, have only one zoran device, this is a waste of kernel memory. Allocating the memory dynamically lets us use only the amount of memory we need. Before: text data bss dec hex filename 64754 9230 90224 164208 28170 drivers/media/video/zr36067.o After: text data bss dec hex filename 64866 9230 112 74208 121e0 drivers/media/video/zr36067.o Signed-off-by: Jean Delvare Acked-by: Ronald Bultje Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran_card.c | 36 +++++++++++++++++++++++------------- drivers/media/video/zoran_card.h | 2 +- drivers/media/video/zoran_driver.c | 4 ++-- 3 files changed, 26 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c index 0929edb2d4f..38d7ed85881 100644 --- a/drivers/media/video/zoran_card.c +++ b/drivers/media/video/zoran_card.c @@ -161,7 +161,7 @@ static struct pci_device_id zr36067_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl); int zoran_num; /* number of Buzs in use */ -struct zoran zoran[BUZ_MAX]; +struct zoran *zoran[BUZ_MAX]; /* videocodec bus functions ZR36060 */ static u32 @@ -1164,7 +1164,7 @@ static void zoran_release (struct zoran *zr) { if (!zr->initialized) - return; + goto exit_free; /* unregister videocodec bus */ if (zr->codec) { struct videocodec_master *master = zr->codec->master_data; @@ -1192,6 +1192,8 @@ zoran_release (struct zoran *zr) iounmap(zr->zr36057_mem); pci_disable_device(zr->pci_dev); video_unregister_device(zr->video_dev); +exit_free: + kfree(zr); } void @@ -1269,8 +1271,14 @@ find_zr36057 (void) while (zoran_num < BUZ_MAX && (dev = pci_get_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) { card_num = card[zoran_num]; - zr = &zoran[zoran_num]; - memset(zr, 0, sizeof(struct zoran)); // Just in case if previous cycle failed + zr = kzalloc(sizeof(struct zoran), GFP_KERNEL); + if (!zr) { + dprintk(1, + KERN_ERR + "%s: find_zr36057() - kzalloc failed\n", + ZORAN_NAME); + continue; + } zr->pci_dev = dev; //zr->zr36057_mem = NULL; zr->id = zoran_num; @@ -1278,7 +1286,7 @@ find_zr36057 (void) spin_lock_init(&zr->spinlock); mutex_init(&zr->resource_lock); if (pci_enable_device(dev)) - continue; + goto zr_free_mem; zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0); pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision); @@ -1294,7 +1302,7 @@ find_zr36057 (void) KERN_ERR "%s: find_zr36057() - no card specified, please use the card=X insmod option\n", ZR_DEVNAME(zr)); - continue; + goto zr_free_mem; } } else { int i; @@ -1333,7 +1341,7 @@ find_zr36057 (void) KERN_ERR "%s: find_zr36057() - unknown card\n", ZR_DEVNAME(zr)); - continue; + goto zr_free_mem; } } } @@ -1343,7 +1351,7 @@ find_zr36057 (void) KERN_ERR "%s: find_zr36057() - invalid cardnum %d\n", ZR_DEVNAME(zr), card_num); - continue; + goto zr_free_mem; } /* even though we make this a non pointer and thus @@ -1361,7 +1369,7 @@ find_zr36057 (void) KERN_ERR "%s: find_zr36057() - ioremap failed\n", ZR_DEVNAME(zr)); - continue; + goto zr_free_mem; } result = request_irq(zr->pci_dev->irq, @@ -1530,7 +1538,7 @@ find_zr36057 (void) } /* Success so keep the pci_dev referenced */ pci_dev_get(zr->pci_dev); - zoran_num++; + zoran[zoran_num++] = zr; continue; // Init errors @@ -1549,6 +1557,8 @@ find_zr36057 (void) free_irq(zr->pci_dev->irq, zr); zr_unmap: iounmap(zr->zr36057_mem); + zr_free_mem: + kfree(zr); continue; } if (dev) /* Clean up ref count on early exit */ @@ -1620,7 +1630,7 @@ init_dc10_cards (void) /* take care of Natoma chipset and a revision 1 zr36057 */ for (i = 0; i < zoran_num; i++) { - struct zoran *zr = &zoran[i]; + struct zoran *zr = zoran[i]; if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) { zr->jpg_buffers.need_contiguous = 1; @@ -1632,7 +1642,7 @@ init_dc10_cards (void) if (zr36057_init(zr) < 0) { for (i = 0; i < zoran_num; i++) - zoran_release(&zoran[i]); + zoran_release(zoran[i]); return -EIO; } zoran_proc_init(zr); @@ -1647,7 +1657,7 @@ unload_dc10_cards (void) int i; for (i = 0; i < zoran_num; i++) - zoran_release(&zoran[i]); + zoran_release(zoran[i]); } module_init(init_dc10_cards); diff --git a/drivers/media/video/zoran_card.h b/drivers/media/video/zoran_card.h index 1b5c4171cf9..e4dc9d29b40 100644 --- a/drivers/media/video/zoran_card.h +++ b/drivers/media/video/zoran_card.h @@ -41,7 +41,7 @@ extern int zr36067_debug; /* Anybody who uses more than four? */ #define BUZ_MAX 4 extern int zoran_num; -extern struct zoran zoran[BUZ_MAX]; +extern struct zoran *zoran[BUZ_MAX]; extern struct video_device zoran_template; diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index e1e1b19a0ae..3ca58221d5a 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -1213,8 +1213,8 @@ zoran_open (struct inode *inode, /* find the device */ for (i = 0; i < zoran_num; i++) { - if (zoran[i].video_dev->minor == minor) { - zr = &zoran[i]; + if (zoran[i]->video_dev->minor == minor) { + zr = zoran[i]; break; } } -- cgit v1.2.3 From ed1aedb136ca42dfd70f5bef202d23994c1a3bae Mon Sep 17 00:00:00 2001 From: Martin Samuelsson Date: Mon, 14 Jul 2008 09:28:59 -0300 Subject: V4L/DVB (8500): zr36067: Load the avs6eyes chip drivers automatically This enables the avs6eyes to load the bt866 and ks0127 drivers automatically. Signed-off-by: Martin Samuelsson Acked-by: Ronald Bultje Signed-off-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran_card.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c index 38d7ed85881..d842a7cb99d 100644 --- a/drivers/media/video/zoran_card.c +++ b/drivers/media/video/zoran_card.c @@ -355,9 +355,15 @@ i2cid_to_modulename (u16 i2c_id) case I2C_DRIVERID_BT856: name = "bt856"; break; + case I2C_DRIVERID_BT866: + name = "bt866"; + break; case I2C_DRIVERID_VPX3220: name = "vpx3220"; break; + case I2C_DRIVERID_KS0127: + name = "ks0127"; + break; } return name; -- cgit v1.2.3 From feb75f07102a85026d41e2c4e4113c34dd035c30 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 27 Jul 2008 06:30:21 -0300 Subject: V4L/DVB (8504): s2255drv: add missing header Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s2255drv.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c index 9ff5403483e..92dfb1845ff 100644 --- a/drivers/media/video/s2255drv.c +++ b/drivers/media/video/s2255drv.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 1052efe0fc69130d9d6a44bc9ceecd229221d9a1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 26 Jul 2008 09:01:24 -0300 Subject: V4L/DVB (8505): saa7134-empress.c: fix deadlock ts_release() locked a mutex that videobuf_stop() also tried to obtain. But ts_release() shouldn't hold that mutex at all. Make empress_users atomic as well to prevent possible race condition. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-empress.c | 12 ++++-------- drivers/media/video/saa7134/saa7134.h | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 8b3f9516778..2ecfbd1b41f 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -89,14 +89,14 @@ static int ts_open(struct inode *inode, struct file *file) err = -EBUSY; if (!mutex_trylock(&dev->empress_tsq.vb_lock)) goto done; - if (dev->empress_users) + if (atomic_read(&dev->empress_users)) goto done_up; /* Unmute audio */ saa_writeb(SAA7134_AUDIO_MUTE_CTRL, saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6)); - dev->empress_users++; + atomic_inc(&dev->empress_users); file->private_data = dev; err = 0; @@ -110,8 +110,6 @@ static int ts_release(struct inode *inode, struct file *file) { struct saa7134_dev *dev = file->private_data; - mutex_lock(&dev->empress_tsq.vb_lock); - videobuf_stop(&dev->empress_tsq); videobuf_mmap_free(&dev->empress_tsq); @@ -122,9 +120,7 @@ static int ts_release(struct inode *inode, struct file *file) saa_writeb(SAA7134_AUDIO_MUTE_CTRL, saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6)); - dev->empress_users--; - - mutex_unlock(&dev->empress_tsq.vb_lock); + atomic_dec(&dev->empress_users); return 0; } @@ -447,7 +443,7 @@ static void empress_signal_update(struct work_struct *work) ts_reset_encoder(dev); } else { dprintk("video signal acquired\n"); - if (dev->empress_users) + if (atomic_read(&dev->empress_users)) ts_init_encoder(dev); } } diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index ade4e19799e..ed20dd56379 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -561,7 +561,7 @@ struct saa7134_dev { /* SAA7134_MPEG_EMPRESS only */ struct video_device *empress_dev; struct videobuf_queue empress_tsq; - unsigned int empress_users; + atomic_t empress_users; struct work_struct empress_workqueue; int empress_started; -- cgit v1.2.3 From 531d83a3d39280d191e2b1f0b540dbad22731579 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 26 Jul 2008 09:04:06 -0300 Subject: V4L/DVB (8506): empress: fix control handling oops Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-empress.c | 20 ++++++++++++-- drivers/media/video/saa7134/saa7134-video.c | 40 +++++++++++++++++++-------- drivers/media/video/saa7134/saa7134.h | 4 +-- 3 files changed, 48 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 2ecfbd1b41f..cd52d5be404 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -329,6 +329,22 @@ static int empress_g_ext_ctrls(struct file *file, void *priv, return saa7134_i2c_call_saa6752(dev, VIDIOC_G_EXT_CTRLS, ctrls); } +static int empress_g_ctrl(struct file *file, void *priv, + struct v4l2_control *c) +{ + struct saa7134_dev *dev = file->private_data; + + return saa7134_g_ctrl_internal(dev, NULL, c); +} + +static int empress_s_ctrl(struct file *file, void *priv, + struct v4l2_control *c) +{ + struct saa7134_dev *dev = file->private_data; + + return saa7134_s_ctrl_internal(dev, NULL, c); +} + static int empress_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c) { @@ -415,8 +431,8 @@ static const struct v4l2_ioctl_ops ts_ioctl_ops = { .vidioc_queryctrl = empress_queryctrl, .vidioc_querymenu = empress_querymenu, - .vidioc_g_ctrl = saa7134_g_ctrl, - .vidioc_s_ctrl = saa7134_s_ctrl, + .vidioc_g_ctrl = empress_g_ctrl, + .vidioc_s_ctrl = empress_s_ctrl, }; /* ----------------------------------------------------------- */ diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 5e9cfc891be..eb824897416 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1112,10 +1112,8 @@ static struct videobuf_queue_ops video_qops = { /* ------------------------------------------------------------------ */ -int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) +int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c) { - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; const struct v4l2_queryctrl* ctrl; ctrl = ctrl_by_id(c->id); @@ -1160,20 +1158,31 @@ int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) } return 0; } -EXPORT_SYMBOL_GPL(saa7134_g_ctrl); +EXPORT_SYMBOL_GPL(saa7134_g_ctrl_internal); + +static int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) +{ + struct saa7134_fh *fh = priv; + + return saa7134_g_ctrl_internal(fh->dev, fh, c); +} -int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c) +int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c) { const struct v4l2_queryctrl* ctrl; - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; unsigned long flags; int restart_overlay = 0; - int err = -EINVAL; + int err; - err = v4l2_prio_check(&dev->prio, &fh->prio); - if (0 != err) - return err; + /* When called from the empress code fh == NULL. + That needs to be fixed somehow, but for now this is + good enough. */ + if (fh) { + err = v4l2_prio_check(&dev->prio, &fh->prio); + if (0 != err) + return err; + } + err = -EINVAL; mutex_lock(&dev->lock); @@ -1274,7 +1283,14 @@ error: mutex_unlock(&dev->lock); return err; } -EXPORT_SYMBOL_GPL(saa7134_s_ctrl); +EXPORT_SYMBOL_GPL(saa7134_s_ctrl_internal); + +static int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c) +{ + struct saa7134_fh *fh = f; + + return saa7134_s_ctrl_internal(fh->dev, fh, c); +} /* ------------------------------------------------------------------ */ diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index ed20dd56379..a0884f639f6 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -663,8 +663,8 @@ extern unsigned int video_debug; extern struct video_device saa7134_video_template; extern struct video_device saa7134_radio_template; -int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c); -int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c); +int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c); +int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c); int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c); int saa7134_videoport_init(struct saa7134_dev *dev); -- cgit v1.2.3 From 353facd4ab5acc6e9d83985eec9ca17e5d0cb470 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 26 Jul 2008 18:28:26 -0300 Subject: V4L/DVB (8509): pvrusb2: fix device descriptions for HVR-1900 & HVR-1950 Acked-by: Mike Isely Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-devattr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index e3b05119708..88e17516843 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -330,7 +330,7 @@ static const char *pvr2_fw1_names_73xxx[] = { }; static const struct pvr2_device_desc pvr2_device_73xxx = { - .description = "WinTV PVR USB2 Model Category 73xxx", + .description = "WinTV HVR-1900 Model Category 73xxx", .shortname = "73xxx", .client_modules.lst = pvr2_client_73xxx, .client_modules.cnt = ARRAY_SIZE(pvr2_client_73xxx), @@ -439,7 +439,7 @@ static const char *pvr2_fw1_names_75xxx[] = { }; static const struct pvr2_device_desc pvr2_device_750xx = { - .description = "WinTV PVR USB2 Model Category 750xx", + .description = "WinTV HVR-1950 Model Category 750xx", .shortname = "750xx", .client_modules.lst = pvr2_client_75xxx, .client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx), @@ -461,7 +461,7 @@ static const struct pvr2_device_desc pvr2_device_750xx = { }; static const struct pvr2_device_desc pvr2_device_751xx = { - .description = "WinTV PVR USB2 Model Category 751xx", + .description = "WinTV HVR-1950 Model Category 751xx", .shortname = "751xx", .client_modules.lst = pvr2_client_75xxx, .client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx), -- cgit v1.2.3 From c6edaf1674d3c17770b1c9966306b802adb21a2b Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Wed, 23 Jul 2008 03:24:06 -0300 Subject: V4L/DVB (8511): gspca: Get the card name of QUERYCAP from the usb product name. This is a preliminary for using the driver_info of the struct usb_device_id to handle the specific per webcam information. Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 2a416cf205a..ab053a26023 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -834,7 +834,16 @@ static int vidioc_querycap(struct file *file, void *priv, memset(cap, 0, sizeof *cap); strncpy(cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver); - strncpy(cap->card, gspca_dev->cam.dev_name, sizeof cap->card); +/* strncpy(cap->card, gspca_dev->cam.dev_name, sizeof cap->card); */ + if (gspca_dev->dev->product != NULL) { + strncpy(cap->card, gspca_dev->dev->product, + sizeof cap->card); + } else { + snprintf(cap->card, sizeof cap->card, + "USB Camera (%04x:%04x)", + le16_to_cpu(gspca_dev->dev->descriptor.idVendor), + le16_to_cpu(gspca_dev->dev->descriptor.idProduct)); + } strncpy(cap->bus_info, gspca_dev->dev->bus->bus_name, sizeof cap->bus_info); cap->version = DRIVER_VERSION_NUMBER; -- cgit v1.2.3 From 07767ebda385956bd2b193f9820de719475bfe6e Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Wed, 23 Jul 2008 03:39:42 -0300 Subject: V4L/DVB (8512): gspca: Do not use the driver_info field of usb_device_id. The field driver_info will be used to handle the specific per webcam information. Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/conex.c | 1 - drivers/media/video/gspca/etoms.c | 1 - drivers/media/video/gspca/mars.c | 1 - drivers/media/video/gspca/ov519.c | 1 - drivers/media/video/gspca/pac7311.c | 1 - drivers/media/video/gspca/sonixj.c | 1 - drivers/media/video/gspca/spca500.c | 1 - drivers/media/video/gspca/spca501.c | 1 - drivers/media/video/gspca/spca505.c | 1 - drivers/media/video/gspca/spca506.c | 1 - drivers/media/video/gspca/spca508.c | 1 - drivers/media/video/gspca/stk014.c | 1 - drivers/media/video/gspca/sunplus.c | 1 - drivers/media/video/gspca/t613.c | 1 - drivers/media/video/gspca/tv8532.c | 1 - drivers/media/video/gspca/vc032x.c | 1 - drivers/media/video/gspca/zc3xx.c | 1 - 17 files changed, 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c index 18c1dec2f76..f5ef7599d3c 100644 --- a/drivers/media/video/gspca/conex.c +++ b/drivers/media/video/gspca/conex.c @@ -815,7 +815,6 @@ static int sd_config(struct gspca_dev *gspca_dev, struct cam *cam; cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; cam->cam_mode = vga_mode; cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c index 6f2f1d24b7e..7529bb0bf6f 100644 --- a/drivers/media/video/gspca/etoms.c +++ b/drivers/media/video/gspca/etoms.c @@ -617,7 +617,6 @@ static int sd_config(struct gspca_dev *gspca_dev, /* break; */ } cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 1; if (sd->sensor == SENSOR_PAS106) { cam->cam_mode = sif_mode; diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c index a4706162f41..2d47876bfec 100644 --- a/drivers/media/video/gspca/mars.c +++ b/drivers/media/video/gspca/mars.c @@ -137,7 +137,6 @@ static int sd_config(struct gspca_dev *gspca_dev, struct cam *cam; cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; cam->cam_mode = vga_mode; cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index f15bec7080c..9109cbbb6fc 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -1372,7 +1372,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = sif_mode; cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; } - cam->dev_name = (char *) id->driver_info; sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value; diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c index 2267ae7cb87..ad802a72cf0 100644 --- a/drivers/media/video/gspca/pac7311.c +++ b/drivers/media/video/gspca/pac7311.c @@ -263,7 +263,6 @@ static int sd_config(struct gspca_dev *gspca_dev, reg_w(gspca_dev, 0x3e, 0x20); cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x05; cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 35b1a3ee4c3..3f8418c7e5f 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -976,7 +976,6 @@ static int sd_config(struct gspca_dev *gspca_dev, } cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c index 8c83823745f..2b8ae8095b0 100644 --- a/drivers/media/video/gspca/spca500.c +++ b/drivers/media/video/gspca/spca500.c @@ -728,7 +728,6 @@ static int sd_config(struct gspca_dev *gspca_dev, break; } cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; if (sd->subtype != LogitechClickSmart310) { cam->cam_mode = vga_mode; diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c index 6537acee89d..a695c42e10c 100644 --- a/drivers/media/video/gspca/spca501.c +++ b/drivers/media/video/gspca/spca501.c @@ -1973,7 +1973,6 @@ static int sd_config(struct gspca_dev *gspca_dev, break; } cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; cam->cam_mode = vga_mode; cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c index 1bb23d03f04..adff24f503b 100644 --- a/drivers/media/video/gspca/spca505.c +++ b/drivers/media/video/gspca/spca505.c @@ -662,7 +662,6 @@ static int sd_config(struct gspca_dev *gspca_dev, } cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; cam->cam_mode = vga_mode; if (sd->subtype != IntelPCCameraPro) diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c index 40e8541b2b8..36dc13c11cb 100644 --- a/drivers/media/video/gspca/spca506.c +++ b/drivers/media/video/gspca/spca506.c @@ -307,7 +307,6 @@ static int sd_config(struct gspca_dev *gspca_dev, struct cam *cam; cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; cam->cam_mode = vga_mode; cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c index 362f645d08c..eff5eda70e6 100644 --- a/drivers/media/video/gspca/spca508.c +++ b/drivers/media/video/gspca/spca508.c @@ -1541,7 +1541,6 @@ static int sd_config(struct gspca_dev *gspca_dev, PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1); cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; cam->cam_mode = sif_mode; cam->nmodes = ARRAY_SIZE(sif_mode); diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c index 90efde17b08..f6390b49f69 100644 --- a/drivers/media/video/gspca/stk014.c +++ b/drivers/media/video/gspca/stk014.c @@ -296,7 +296,6 @@ static int sd_config(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; struct cam *cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x02; gspca_dev->cam.cam_mode = vga_mode; gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c index 53e20275f26..030cb18b355 100644 --- a/drivers/media/video/gspca/sunplus.c +++ b/drivers/media/video/gspca/sunplus.c @@ -1021,7 +1021,6 @@ static int sd_config(struct gspca_dev *gspca_dev, } cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; switch (sd->bridge) { diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c index fc1c62e5a2f..f7ea9a74272 100644 --- a/drivers/media/video/gspca/t613.c +++ b/drivers/media/video/gspca/t613.c @@ -422,7 +422,6 @@ static int sd_config(struct gspca_dev *gspca_dev, struct cam *cam; cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; cam->cam_mode = vga_mode_t16; diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c index cb2d9da2a22..b024aca9b10 100644 --- a/drivers/media/video/gspca/tv8532.c +++ b/drivers/media/video/gspca/tv8532.c @@ -246,7 +246,6 @@ static int sd_config(struct gspca_dev *gspca_dev, tv_8532WriteEEprom(gspca_dev); cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 1; cam->cam_mode = sif_mode; cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c index e306ac42029..46cff48e629 100644 --- a/drivers/media/video/gspca/vc032x.c +++ b/drivers/media/video/gspca/vc032x.c @@ -1438,7 +1438,6 @@ static int sd_config(struct gspca_dev *gspca_dev, } cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x02; if (sd->bridge == BRIDGE_VC0321) { cam->cam_mode = vc0321_mode; diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index f8d6f1780a4..acd538da078 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -7153,7 +7153,6 @@ static int sd_config(struct gspca_dev *gspca_dev, } cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; /*fixme:test*/ gspca_dev->nbalt--; -- cgit v1.2.3 From 9d64fdb15b1b9ce9144cfde4001e9194ccde42d1 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Fri, 25 Jul 2008 08:53:03 -0300 Subject: V4L/DVB (8513): gspca: Set the specific per webcam information in driver_info. This patch removes a big part of the code run at probe time. Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/conex.c | 3 +- drivers/media/video/gspca/etoms.c | 24 +-- drivers/media/video/gspca/mars.c | 3 +- drivers/media/video/gspca/ov519.c | 27 ++- drivers/media/video/gspca/pac207.c | 19 +- drivers/media/video/gspca/pac7311.c | 16 +- drivers/media/video/gspca/sonixj.c | 243 +++++-------------------- drivers/media/video/gspca/spca500.c | 133 ++------------ drivers/media/video/gspca/spca501.c | 69 +------ drivers/media/video/gspca/spca505.c | 29 +-- drivers/media/video/gspca/spca506.c | 10 +- drivers/media/video/gspca/spca508.c | 67 +------ drivers/media/video/gspca/spca561.c | 57 ++---- drivers/media/video/gspca/stk014.c | 3 +- drivers/media/video/gspca/sunplus.c | 349 ++++++++---------------------------- drivers/media/video/gspca/t613.c | 3 +- drivers/media/video/gspca/tv8532.c | 11 +- drivers/media/video/gspca/vc032x.c | 38 +--- drivers/media/video/gspca/zc3xx.c | 125 ++++++------- 19 files changed, 284 insertions(+), 945 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c index f5ef7599d3c..44b0bffeb20 100644 --- a/drivers/media/video/gspca/conex.c +++ b/drivers/media/video/gspca/conex.c @@ -1007,9 +1007,8 @@ static struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x0572, 0x0041), DVNM("Creative Notebook cx11646")}, + {USB_DEVICE(0x0572, 0x0041)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c index 7529bb0bf6f..c8c2f02fcf0 100644 --- a/drivers/media/video/gspca/etoms.c +++ b/drivers/media/video/gspca/etoms.c @@ -599,25 +599,10 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - __u16 vendor; - __u16 product; - - vendor = id->idVendor; - product = id->idProduct; -/* switch (vendor) { */ -/* case 0x102c: * Etoms */ - switch (product) { - case 0x6151: - sd->sensor = SENSOR_PAS106; /* Etoms61x151 */ - break; - case 0x6251: - sd->sensor = SENSOR_TAS5130CXX; /* Etoms61x251 */ - break; -/* } */ -/* break; */ - } + cam = &gspca_dev->cam; cam->epaddr = 1; + sd->sensor = id->driver_info; if (sd->sensor == SENSOR_PAS106) { cam->cam_mode = sif_mode; cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; @@ -907,12 +892,11 @@ static struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static __devinitdata struct usb_device_id device_table[] = { #ifndef CONFIG_USB_ET61X251 - {USB_DEVICE(0x102c, 0x6151), DVNM("Qcam Sangha CIF")}, + {USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106}, #endif - {USB_DEVICE(0x102c, 0x6251), DVNM("Qcam xxxxxx VGA")}, + {USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX}, {} }; diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c index 2d47876bfec..21c4ee56a10 100644 --- a/drivers/media/video/gspca/mars.c +++ b/drivers/media/video/gspca/mars.c @@ -420,9 +420,8 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x093a, 0x050f), DVNM("Mars-Semi Pc-Camera")}, + {USB_DEVICE(0x093a, 0x050f)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index 9109cbbb6fc..83139efc462 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -2125,21 +2125,20 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x4052), DVNM("Creative Live! VISTA IM")}, - {USB_DEVICE(0x041e, 0x405f), DVNM("Creative Live! VISTA VF0330")}, - {USB_DEVICE(0x041e, 0x4060), DVNM("Creative Live! VISTA VF0350")}, - {USB_DEVICE(0x041e, 0x4061), DVNM("Creative Live! VISTA VF0400")}, - {USB_DEVICE(0x041e, 0x4064), DVNM("Creative Live! VISTA VF0420")}, - {USB_DEVICE(0x041e, 0x4068), DVNM("Creative Live! VISTA VF0470")}, - {USB_DEVICE(0x045e, 0x028c), DVNM("Microsoft xbox cam")}, - {USB_DEVICE(0x054c, 0x0154), DVNM("Sonny toy4")}, - {USB_DEVICE(0x054c, 0x0155), DVNM("Sonny toy5")}, - {USB_DEVICE(0x05a9, 0x0519), DVNM("OmniVision")}, - {USB_DEVICE(0x05a9, 0x0530), DVNM("OmniVision")}, - {USB_DEVICE(0x05a9, 0x4519), DVNM("OmniVision")}, - {USB_DEVICE(0x05a9, 0x8519), DVNM("OmniVision")}, + {USB_DEVICE(0x041e, 0x4052)}, + {USB_DEVICE(0x041e, 0x405f)}, + {USB_DEVICE(0x041e, 0x4060)}, + {USB_DEVICE(0x041e, 0x4061)}, + {USB_DEVICE(0x041e, 0x4064)}, + {USB_DEVICE(0x041e, 0x4068)}, + {USB_DEVICE(0x045e, 0x028c)}, + {USB_DEVICE(0x054c, 0x0154)}, + {USB_DEVICE(0x054c, 0x0155)}, + {USB_DEVICE(0x05a9, 0x0519)}, + {USB_DEVICE(0x05a9, 0x0530)}, + {USB_DEVICE(0x05a9, 0x4519)}, + {USB_DEVICE(0x05a9, 0x8519)}, {} }; #undef DVNAME diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c index f790746370d..7ef18d57881 100644 --- a/drivers/media/video/gspca/pac207.c +++ b/drivers/media/video/gspca/pac207.c @@ -570,17 +570,16 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x4028), DVNM("Creative Webcam Vista Plus")}, - {USB_DEVICE(0x093a, 0x2460), DVNM("Q-Tec Webcam 100")}, - {USB_DEVICE(0x093a, 0x2463), DVNM("Philips spc200nc pac207")}, - {USB_DEVICE(0x093a, 0x2464), DVNM("Labtec Webcam 1200")}, - {USB_DEVICE(0x093a, 0x2468), DVNM("PAC207")}, - {USB_DEVICE(0x093a, 0x2470), DVNM("Genius GF112")}, - {USB_DEVICE(0x093a, 0x2471), DVNM("Genius VideoCam GE111")}, - {USB_DEVICE(0x093a, 0x2472), DVNM("Genius VideoCam GE110")}, - {USB_DEVICE(0x2001, 0xf115), DVNM("D-Link DSB-C120")}, + {USB_DEVICE(0x041e, 0x4028)}, + {USB_DEVICE(0x093a, 0x2460)}, + {USB_DEVICE(0x093a, 0x2463)}, + {USB_DEVICE(0x093a, 0x2464)}, + {USB_DEVICE(0x093a, 0x2468)}, + {USB_DEVICE(0x093a, 0x2470)}, + {USB_DEVICE(0x093a, 0x2471)}, + {USB_DEVICE(0x093a, 0x2472)}, + {USB_DEVICE(0x2001, 0xf115)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c index ad802a72cf0..ea3d7021f40 100644 --- a/drivers/media/video/gspca/pac7311.c +++ b/drivers/media/video/gspca/pac7311.c @@ -709,16 +709,14 @@ static struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x093a, 0x2600), DVNM("Typhoon")}, - {USB_DEVICE(0x093a, 0x2601), DVNM("Philips SPC610NC")}, - {USB_DEVICE(0x093a, 0x2603), DVNM("PAC7312")}, - {USB_DEVICE(0x093a, 0x2608), DVNM("Trust WB-3300p")}, - {USB_DEVICE(0x093a, 0x260e), DVNM("Gigaware VGA PC Camera")}, - /* and also ', Trust WB-3350p, SIGMA cam 2350' */ - {USB_DEVICE(0x093a, 0x260f), DVNM("SnakeCam")}, - {USB_DEVICE(0x093a, 0x2621), DVNM("PAC731x")}, + {USB_DEVICE(0x093a, 0x2600)}, + {USB_DEVICE(0x093a, 0x2601)}, + {USB_DEVICE(0x093a, 0x2603)}, + {USB_DEVICE(0x093a, 0x2608)}, + {USB_DEVICE(0x093a, 0x260e)}, + {USB_DEVICE(0x093a, 0x260f)}, + {USB_DEVICE(0x093a, 0x2621)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 3f8418c7e5f..46f2cf66d48 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -795,191 +795,16 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - __u16 product; - - product = id->idProduct; - sd->sensor = -1; - switch (id->idVendor) { - case 0x0458: /* Genius */ -/* switch (product) { - case 0x7025: */ - sd->bridge = BRIDGE_SN9C120; - sd->sensor = SENSOR_MI0360; - sd->i2c_base = 0x5d; -/* break; - } */ - break; - case 0x045e: -/* switch (product) { - case 0x00f5: - case 0x00f7: */ - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_OV7660; - sd->i2c_base = 0x21; -/* break; - } */ - break; - case 0x0471: /* Philips */ -/* switch (product) { - case 0x0327: - case 0x0328: - case 0x0330: */ - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_MI0360; - sd->i2c_base = 0x5d; -/* break; - } */ - break; - case 0x0c45: /* Sonix */ - switch (product) { - case 0x6040: - sd->bridge = BRIDGE_SN9C102P; -/* sd->sensor = SENSOR_MI0360; * from BW600.inf */ -/*fixme: MI0360 base=5d ? */ - sd->sensor = SENSOR_HV7131R; /* gspcav1 value */ - sd->i2c_base = 0x11; - break; -/* case 0x607a: * from BW600.inf - sd->bridge = BRIDGE_SN9C102P; - sd->sensor = SENSOR_OV7648; - sd->i2c_base = 0x??; - break; */ - case 0x607c: - sd->bridge = BRIDGE_SN9C102P; - sd->sensor = SENSOR_HV7131R; - sd->i2c_base = 0x11; - break; -/* case 0x607e: * from BW600.inf - sd->bridge = BRIDGE_SN9C102P; - sd->sensor = SENSOR_OV7630; - sd->i2c_base = 0x??; - break; */ - case 0x60c0: - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_MI0360; - sd->i2c_base = 0x5d; - break; -/* case 0x60c8: * from BW600.inf - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_OM6801; - sd->i2c_base = 0x??; - break; */ -/* case 0x60cc: * from BW600.inf - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_HV7131GP; - sd->i2c_base = 0x??; - break; */ - case 0x60ec: - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_MO4000; - sd->i2c_base = 0x21; - break; -/* case 0x60ef: * from BW600.inf - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_ICM105C; - sd->i2c_base = 0x??; - break; */ -/* case 0x60fa: * from BW600.inf - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_OV7648; - sd->i2c_base = 0x??; - break; */ - case 0x60fb: - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_OV7660; - sd->i2c_base = 0x21; - break; - case 0x60fc: - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_HV7131R; - sd->i2c_base = 0x11; - break; -/* case 0x60fe: * from BW600.inf - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_OV7630; - sd->i2c_base = 0x??; - break; */ -/* case 0x6108: * from BW600.inf - sd->bridge = BRIDGE_SN9C120; - sd->sensor = SENSOR_OM6801; - sd->i2c_base = 0x??; - break; */ -/* case 0x6122: * from BW600.inf - sd->bridge = BRIDGE_SN9C110; - sd->sensor = SENSOR_ICM105C; - sd->i2c_base = 0x??; - break; */ - case 0x612a: -/* sd->bridge = BRIDGE_SN9C110; * in BW600.inf */ - sd->bridge = BRIDGE_SN9C325; - sd->sensor = SENSOR_OV7648; - sd->i2c_base = 0x21; -/*fixme: sensor_init has base = 00 et 6e!*/ - break; -/* case 0x6123: * from BW600.inf - sd->bridge = BRIDGE_SN9C110; - sd->sensor = SENSOR_SanyoCCD; - sd->i2c_base = 0x??; - break; */ - case 0x612c: - sd->bridge = BRIDGE_SN9C110; - sd->sensor = SENSOR_MO4000; - sd->i2c_base = 0x21; - break; -/* case 0x612e: * from BW600.inf - sd->bridge = BRIDGE_SN9C110; - sd->sensor = SENSOR_OV7630; - sd->i2c_base = 0x??; - break; */ -/* case 0x612f: * from BW600.inf - sd->bridge = BRIDGE_SN9C110; - sd->sensor = SENSOR_ICM105C; - sd->i2c_base = 0x??; - break; */ - case 0x6130: - sd->bridge = BRIDGE_SN9C120; - sd->sensor = SENSOR_MI0360; - sd->i2c_base = 0x5d; - break; - case 0x6138: - sd->bridge = BRIDGE_SN9C120; - sd->sensor = SENSOR_MO4000; - sd->i2c_base = 0x21; - break; -/* case 0x613a: * from BW600.inf - sd->bridge = BRIDGE_SN9C120; - sd->sensor = SENSOR_OV7648; - sd->i2c_base = 0x??; - break; */ - case 0x613b: - sd->bridge = BRIDGE_SN9C120; - sd->sensor = SENSOR_OV7660; - sd->i2c_base = 0x21; - break; - case 0x613c: - sd->bridge = BRIDGE_SN9C120; - sd->sensor = SENSOR_HV7131R; - sd->i2c_base = 0x11; - break; -/* case 0x613e: * from BW600.inf - sd->bridge = BRIDGE_SN9C120; - sd->sensor = SENSOR_OV7630; - sd->i2c_base = 0x??; - break; */ - } - break; - } - if (sd->sensor < 0) { - PDEBUG(D_ERR, "Invalid vendor/product %04x:%04x", - id->idVendor, product); - return -EINVAL; - } cam = &gspca_dev->cam; cam->epaddr = 0x01; cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); + sd->bridge = id->driver_info >> 16; + sd->sensor = id->driver_info >> 8; + sd->i2c_base = id->driver_info; + sd->qindex = 4; /* set the quantization table */ sd->brightness = BRIGHTNESS_DEF; sd->contrast = CONTRAST_DEF; @@ -1596,29 +1421,51 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name +#define BSI(bridge, sensor, i2c_addr) \ + .driver_info = (BRIDGE_ ## bridge << 16) \ + | (SENSOR_ ## sensor << 8) \ + | (i2c_addr) static const __devinitdata struct usb_device_id device_table[] = { #ifndef CONFIG_USB_SN9C102 - {USB_DEVICE(0x0458, 0x7025), DVNM("Genius Eye 311Q")}, - {USB_DEVICE(0x045e, 0x00f5), DVNM("MicroSoft VX3000")}, - {USB_DEVICE(0x045e, 0x00f7), DVNM("MicroSoft VX1000")}, - {USB_DEVICE(0x0471, 0x0327), DVNM("Philips SPC 600 NC")}, - {USB_DEVICE(0x0471, 0x0328), DVNM("Philips SPC 700 NC")}, + {USB_DEVICE(0x0458, 0x7025), BSI(SN9C120, MI0360, 0x5d)}, + {USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)}, + {USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)}, + {USB_DEVICE(0x0471, 0x0327), BSI(SN9C105, MI0360, 0x5d)}, + {USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)}, #endif - {USB_DEVICE(0x0471, 0x0330), DVNM("Philips SPC 710NC")}, - {USB_DEVICE(0x0c45, 0x6040), DVNM("Speed NVC 350K")}, - {USB_DEVICE(0x0c45, 0x607c), DVNM("Sonix sn9c102p Hv7131R")}, - {USB_DEVICE(0x0c45, 0x60c0), DVNM("Sangha Sn535")}, - {USB_DEVICE(0x0c45, 0x60ec), DVNM("SN9C105+MO4000")}, - {USB_DEVICE(0x0c45, 0x60fb), DVNM("Surfer NoName")}, - {USB_DEVICE(0x0c45, 0x60fc), DVNM("LG-LIC300")}, - {USB_DEVICE(0x0c45, 0x612a), DVNM("Avant Camera")}, - {USB_DEVICE(0x0c45, 0x612c), DVNM("Typhoon Rasy Cam 1.3MPix")}, + {USB_DEVICE(0x0471, 0x0330), BSI(SN9C105, MI0360, 0x5d)}, + {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, HV7131R, 0x11)}, +/* bw600.inf: + {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, MI0360, 0x5d)}, */ +/* {USB_DEVICE(0x0c45, 0x603a), BSI(SN9C102P, OV7648, 0x??)}, */ +/* {USB_DEVICE(0x0c45, 0x607a), BSI(SN9C102P, OV7648, 0x??)}, */ + {USB_DEVICE(0x0c45, 0x607c), BSI(SN9C102P, HV7131R, 0x11)}, +/* {USB_DEVICE(0x0c45, 0x607e), BSI(SN9C102P, OV7630, 0x??)}, */ + {USB_DEVICE(0x0c45, 0x60c0), BSI(SN9C105, MI0360, 0x5d)}, +/* {USB_DEVICE(0x0c45, 0x60c8), BSI(SN9C105, OM6801, 0x??)}, */ +/* {USB_DEVICE(0x0c45, 0x60cc), BSI(SN9C105, HV7131GP, 0x??)}, */ + {USB_DEVICE(0x0c45, 0x60ec), BSI(SN9C105, MO4000, 0x21)}, +/* {USB_DEVICE(0x0c45, 0x60ef), BSI(SN9C105, ICM105C, 0x??)}, */ +/* {USB_DEVICE(0x0c45, 0x60fa), BSI(SN9C105, OV7648, 0x??)}, */ + {USB_DEVICE(0x0c45, 0x60fb), BSI(SN9C105, OV7660, 0x21)}, + {USB_DEVICE(0x0c45, 0x60fc), BSI(SN9C105, HV7131R, 0x11)}, +/* {USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x??)}, */ +/* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */ +/* {USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */ +/* {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */ + {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C325, OV7648, 0x21)}, +/* bw600.inf: + {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, */ + {USB_DEVICE(0x0c45, 0x612c), BSI(SN9C110, MO4000, 0x21)}, +/* {USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x??)}, */ +/* {USB_DEVICE(0x0c45, 0x612f), BSI(SN9C110, ICM105C, 0x??)}, */ #ifndef CONFIG_USB_SN9C102 - {USB_DEVICE(0x0c45, 0x6130), DVNM("Sonix Pccam")}, - {USB_DEVICE(0x0c45, 0x6138), DVNM("Sn9c120 Mo4000")}, - {USB_DEVICE(0x0c45, 0x613b), DVNM("Surfer SN-206")}, - {USB_DEVICE(0x0c45, 0x613c), DVNM("Sonix Pccam168")}, + {USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)}, + {USB_DEVICE(0x0c45, 0x6138), BSI(SN9C120, MO4000, 0x21)}, +/* {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x??)}, */ + {USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)}, + {USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)}, +/* {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x??)}, */ #endif {} }; diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c index 2b8ae8095b0..66cf2b684b7 100644 --- a/drivers/media/video/gspca/spca500.c +++ b/drivers/media/video/gspca/spca500.c @@ -627,108 +627,10 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - __u16 vendor; - __u16 product; - - vendor = id->idVendor; - product = id->idProduct; - switch (vendor) { - case 0x040a: /* Kodak cameras */ -/* switch (product) { */ -/* case 0x0300: */ - sd->subtype = KodakEZ200; -/* break; */ -/* } */ - break; - case 0x041e: /* Creative cameras */ -/* switch (product) { */ -/* case 0x400a: */ - sd->subtype = CreativePCCam300; -/* break; */ -/* } */ - break; - case 0x046d: /* Logitech Labtec */ - switch (product) { - case 0x0890: - sd->subtype = LogitechTraveler; - break; - case 0x0900: - sd->subtype = LogitechClickSmart310; - break; - case 0x0901: - sd->subtype = LogitechClickSmart510; - break; - } - break; - case 0x04a5: /* Benq */ -/* switch (product) { */ -/* case 0x300c: */ - sd->subtype = BenqDC1016; -/* break; */ -/* } */ - break; - case 0x04fc: /* SunPlus */ -/* switch (product) { */ -/* case 0x7333: */ - sd->subtype = PalmPixDC85; -/* break; */ -/* } */ - break; - case 0x055f: /* Mustek cameras */ - switch (product) { - case 0xc200: - sd->subtype = MustekGsmart300; - break; - case 0xc220: - sd->subtype = Gsmartmini; - break; - } - break; - case 0x06bd: /* Agfa Cl20 */ -/* switch (product) { */ -/* case 0x0404: */ - sd->subtype = AgfaCl20; -/* break; */ -/* } */ - break; - case 0x06be: /* Optimedia */ -/* switch (product) { */ -/* case 0x0800: */ - sd->subtype = Optimedia; -/* break; */ -/* } */ - break; - case 0x084d: /* D-Link / Minton */ -/* switch (product) { */ -/* case 0x0003: * DSC-350 / S-Cam F5 */ - sd->subtype = DLinkDSC350; -/* break; */ -/* } */ - break; - case 0x08ca: /* Aiptek */ -/* switch (product) { */ -/* case 0x0103: */ - sd->subtype = AiptekPocketDV; -/* break; */ -/* } */ - break; - case 0x2899: /* ToptroIndustrial */ -/* switch (product) { */ -/* case 0x012c: */ - sd->subtype = ToptroIndus; -/* break; */ -/* } */ - break; - case 0x8086: /* Intel */ -/* switch (product) { */ -/* case 0x0630: * Pocket PC Camera */ - sd->subtype = IntelPocketPCCamera; -/* break; */ -/* } */ - break; - } + cam = &gspca_dev->cam; cam->epaddr = 0x01; + sd->subtype = id->driver_info; if (sd->subtype != LogitechClickSmart310) { cam->cam_mode = vga_mode; cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; @@ -1158,23 +1060,22 @@ static struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x040a, 0x0300), DVNM("Kodak EZ200")}, - {USB_DEVICE(0x041e, 0x400a), DVNM("Creative PC-CAM 300")}, - {USB_DEVICE(0x046d, 0x0890), DVNM("Logitech QuickCam traveler")}, - {USB_DEVICE(0x046d, 0x0900), DVNM("Logitech Inc. ClickSmart 310")}, - {USB_DEVICE(0x046d, 0x0901), DVNM("Logitech Inc. ClickSmart 510")}, - {USB_DEVICE(0x04a5, 0x300c), DVNM("Benq DC1016")}, - {USB_DEVICE(0x04fc, 0x7333), DVNM("PalmPixDC85")}, - {USB_DEVICE(0x055f, 0xc200), DVNM("Mustek Gsmart 300")}, - {USB_DEVICE(0x055f, 0xc220), DVNM("Gsmart Mini")}, - {USB_DEVICE(0x06bd, 0x0404), DVNM("Agfa CL20")}, - {USB_DEVICE(0x06be, 0x0800), DVNM("Optimedia")}, - {USB_DEVICE(0x084d, 0x0003), DVNM("D-Link DSC-350")}, - {USB_DEVICE(0x08ca, 0x0103), DVNM("Aiptek PocketDV")}, - {USB_DEVICE(0x2899, 0x012c), DVNM("Toptro Industrial")}, - {USB_DEVICE(0x8086, 0x0630), DVNM("Intel Pocket PC Camera")}, + {USB_DEVICE(0x040a, 0x0300), KodakEZ200}, + {USB_DEVICE(0x041e, 0x400a), CreativePCCam300}, + {USB_DEVICE(0x046d, 0x0890), LogitechTraveler}, + {USB_DEVICE(0x046d, 0x0900), LogitechClickSmart310}, + {USB_DEVICE(0x046d, 0x0901), LogitechClickSmart510}, + {USB_DEVICE(0x04a5, 0x300c), BenqDC1016}, + {USB_DEVICE(0x04fc, 0x7333), PalmPixDC85}, + {USB_DEVICE(0x055f, 0xc200), MustekGsmart300}, + {USB_DEVICE(0x055f, 0xc220), Gsmartmini}, + {USB_DEVICE(0x06bd, 0x0404), AgfaCl20}, + {USB_DEVICE(0x06be, 0x0800), Optimedia}, + {USB_DEVICE(0x084d, 0x0003), DLinkDSC350}, + {USB_DEVICE(0x08ca, 0x0103), AiptekPocketDV}, + {USB_DEVICE(0x2899, 0x012c), ToptroIndus}, + {USB_DEVICE(0x8086, 0x0630), IntelPocketPCCamera}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c index a695c42e10c..a8a460c6eb0 100644 --- a/drivers/media/video/gspca/spca501.c +++ b/drivers/media/video/gspca/spca501.c @@ -1920,62 +1920,12 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - __u16 vendor; - __u16 product; - - vendor = id->idVendor; - product = id->idProduct; - switch (vendor) { - case 0x0000: /* Unknow Camera */ -/* switch (product) { */ -/* case 0x0000: */ - sd->subtype = MystFromOriUnknownCamera; -/* break; */ -/* } */ - break; - case 0x040a: /* Kodak cameras */ -/* switch (product) { */ -/* case 0x0002: */ - sd->subtype = KodakDVC325; -/* break; */ -/* } */ - break; - case 0x0497: /* Smile International */ -/* switch (product) { */ -/* case 0xc001: */ - sd->subtype = SmileIntlCamera; -/* break; */ -/* } */ - break; - case 0x0506: /* 3COM cameras */ -/* switch (product) { */ -/* case 0x00df: */ - sd->subtype = ThreeComHomeConnectLite; -/* break; */ -/* } */ - break; - case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */ - switch (product) { - case 0x0401: - sd->subtype = IntelCreateAndShare; - break; - case 0x0402: - sd->subtype = ViewQuestM318B; - break; - } - break; - case 0x1776: /* Arowana */ -/* switch (product) { */ -/* case 0x501c: */ - sd->subtype = Arowana300KCMOSCamera; -/* break; */ -/* } */ - break; - } + cam = &gspca_dev->cam; cam->epaddr = 0x01; cam->cam_mode = vga_mode; cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + sd->subtype = id->driver_info; sd->brightness = sd_ctrls[MY_BRIGHTNESS].qctrl.default_value; sd->contrast = sd_ctrls[MY_CONTRAST].qctrl.default_value; sd->colors = sd_ctrls[MY_COLOR].qctrl.default_value; @@ -2179,15 +2129,14 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x040a, 0x0002), DVNM("Kodak DVC-325")}, - {USB_DEVICE(0x0497, 0xc001), DVNM("Smile International")}, - {USB_DEVICE(0x0506, 0x00df), DVNM("3Com HomeConnect Lite")}, - {USB_DEVICE(0x0733, 0x0401), DVNM("Intel Create and Share")}, - {USB_DEVICE(0x0733, 0x0402), DVNM("ViewQuest M318B")}, - {USB_DEVICE(0x1776, 0x501c), DVNM("Arowana 300K CMOS Camera")}, - {USB_DEVICE(0x0000, 0x0000), DVNM("MystFromOri Unknow Camera")}, + {USB_DEVICE(0x040a, 0x0002), KodakDVC325}, + {USB_DEVICE(0x0497, 0xc001), SmileIntlCamera}, + {USB_DEVICE(0x0506, 0x00df), ThreeComHomeConnectLite}, + {USB_DEVICE(0x0733, 0x0401), IntelCreateAndShare}, + {USB_DEVICE(0x0733, 0x0402), ViewQuestM318B}, + {USB_DEVICE(0x1776, 0x501c), Arowana300KCMOSCamera}, + {USB_DEVICE(0x0000, 0x0000), MystFromOriUnknownCamera}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c index adff24f503b..284d549e4d3 100644 --- a/drivers/media/video/gspca/spca505.c +++ b/drivers/media/video/gspca/spca505.c @@ -638,32 +638,11 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - __u16 vendor; - __u16 product; - - vendor = id->idVendor; - product = id->idProduct; - switch (vendor) { - case 0x041e: /* Creative cameras */ -/* switch (product) { */ -/* case 0x401d: * here505b */ - sd->subtype = Nxultra; -/* break; */ -/* } */ - break; - case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */ -/* switch (product) { */ -/* case 0x0430: */ -/* fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */ - sd->subtype = IntelPCCameraPro; -/* break; */ -/* } */ - break; - } cam = &gspca_dev->cam; cam->epaddr = 0x01; cam->cam_mode = vga_mode; + sd->subtype = id->driver_info; if (sd->subtype != IntelPCCameraPro) cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; else /* no 640x480 for IntelPCCameraPro */ @@ -906,10 +885,10 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x401d), DVNM("Creative Webcam NX ULTRA")}, - {USB_DEVICE(0x0733, 0x0430), DVNM("Intel PC Camera Pro")}, + {USB_DEVICE(0x041e, 0x401d), Nxultra}, + {USB_DEVICE(0x0733, 0x0430), IntelPCCameraPro}, +/*fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */ {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c index 36dc13c11cb..2c281a0563e 100644 --- a/drivers/media/video/gspca/spca506.c +++ b/drivers/media/video/gspca/spca506.c @@ -800,12 +800,12 @@ static struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x06e1, 0xa190), DVNM("ADS Instant VCD")}, -/* {USB_DEVICE(0x0733, 0x0430), DVNM("UsbGrabber PV321c")}, */ - {USB_DEVICE(0x0734, 0x043b), DVNM("3DeMon USB Capture aka")}, - {USB_DEVICE(0x99fa, 0x8988), DVNM("Grandtec V.cap")}, + {USB_DEVICE(0x06e1, 0xa190)}, +/*fixme: may be IntelPCCameraPro BRIDGE_SPCA505 + {USB_DEVICE(0x0733, 0x0430)}, */ + {USB_DEVICE(0x0734, 0x043b)}, + {USB_DEVICE(0x99fa, 0x8988)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c index eff5eda70e6..af531d62856 100644 --- a/drivers/media/video/gspca/spca508.c +++ b/drivers/media/video/gspca/spca508.c @@ -1473,58 +1473,8 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - __u16 product; int data1, data2; - product = id->idProduct; - switch (id->idVendor) { - case 0x0130: /* Clone webcam */ -/* switch (product) { */ -/* case 0x0130: */ - sd->subtype = HamaUSBSightcam; /* same as Hama 0010 */ -/* break; */ -/* } */ - break; - case 0x041e: /* Creative cameras */ -/* switch (product) { */ -/* case 0x4018: */ - sd->subtype = CreativeVista; -/* break; */ -/* } */ - break; - case 0x0461: /* MicroInnovation */ -/* switch (product) { */ -/* case 0x0815: */ - sd->subtype = MicroInnovationIC200; -/* break; */ -/* } */ - break; - case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */ -/* switch (product) { */ -/* case 0x110: */ - sd->subtype = ViewQuestVQ110; -/* break; */ -/* } */ - break; - case 0x0af9: /* Hama cameras */ - switch (product) { - case 0x0010: - sd->subtype = HamaUSBSightcam; - break; - case 0x0011: - sd->subtype = HamaUSBSightcam2; - break; - } - break; - case 0x8086: /* Intel */ -/* switch (product) { */ -/* case 0x0110: */ - sd->subtype = IntelEasyPCCamera; -/* break; */ -/* } */ - break; - } - /* Read from global register the USB product and vendor IDs, just to * prove that we can communicate with the device. This works, which * confirms at we are communicating properly and that the device @@ -1544,6 +1494,8 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->epaddr = 0x01; cam->cam_mode = sif_mode; cam->nmodes = ARRAY_SIZE(sif_mode); + + sd->subtype = id->driver_info; sd->brightness = BRIGHTNESS_DEF; switch (sd->subtype) { @@ -1741,15 +1693,14 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x0130, 0x0130), DVNM("Clone Digital Webcam 11043")}, - {USB_DEVICE(0x041e, 0x4018), DVNM("Creative Webcam Vista (PD1100)")}, - {USB_DEVICE(0x0461, 0x0815), DVNM("Micro Innovation IC200")}, - {USB_DEVICE(0x0733, 0x0110), DVNM("ViewQuest VQ110")}, - {USB_DEVICE(0x0af9, 0x0010), DVNM("Hama USB Sightcam 100")}, - {USB_DEVICE(0x0af9, 0x0011), DVNM("Hama USB Sightcam 100")}, - {USB_DEVICE(0x8086, 0x0110), DVNM("Intel Easy PC Camera")}, + {USB_DEVICE(0x0130, 0x0130), HamaUSBSightcam}, + {USB_DEVICE(0x041e, 0x4018), CreativeVista}, + {USB_DEVICE(0x0461, 0x0815), MicroInnovationIC200}, + {USB_DEVICE(0x0733, 0x0110), ViewQuestVQ110}, + {USB_DEVICE(0x0af9, 0x0010), HamaUSBSightcam}, + {USB_DEVICE(0x0af9, 0x0011), HamaUSBSightcam2}, + {USB_DEVICE(0x8086, 0x0110), IntelEasyPCCamera}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c index 85c37f396aa..3b46f7dda64 100644 --- a/drivers/media/video/gspca/spca561.c +++ b/drivers/media/video/gspca/spca561.c @@ -579,35 +579,15 @@ static int sd_config(struct gspca_dev *gspca_dev, PDEBUG(D_PROBE, "Bad vendor / product from device"); return -EINVAL; } - switch (product) { - case 0x0928: - case 0x0929: - case 0x092a: - case 0x092b: - case 0x092c: - case 0x092d: - case 0x092e: - case 0x092f: - case 0x403b: - sd->chip_revision = Rev012A; - break; - default: -/* case 0x0561: - case 0x0815: * ?? in spca508.c - case 0x401a: - case 0x7004: - case 0x7e50: - case 0xa001: - case 0xcdee: */ - sd->chip_revision = Rev072A; - break; - } + cam = &gspca_dev->cam; cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */ cam->cam_mode = sif_mode; cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; + + sd->chip_revision = id->driver_info; sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value; @@ -994,23 +974,22 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x401a), DVNM("Creative Webcam Vista (PD1100)")}, - {USB_DEVICE(0x041e, 0x403b), DVNM("Creative Webcam Vista (VF0010)")}, - {USB_DEVICE(0x0458, 0x7004), DVNM("Genius VideoCAM Express V2")}, - {USB_DEVICE(0x046d, 0x0928), DVNM("Logitech QC Express Etch2")}, - {USB_DEVICE(0x046d, 0x0929), DVNM("Labtec Webcam Elch2")}, - {USB_DEVICE(0x046d, 0x092a), DVNM("Logitech QC for Notebook")}, - {USB_DEVICE(0x046d, 0x092b), DVNM("Labtec Webcam Plus")}, - {USB_DEVICE(0x046d, 0x092c), DVNM("Logitech QC chat Elch2")}, - {USB_DEVICE(0x046d, 0x092d), DVNM("Logitech QC Elch2")}, - {USB_DEVICE(0x046d, 0x092e), DVNM("Logitech QC Elch2")}, - {USB_DEVICE(0x046d, 0x092f), DVNM("Logitech QC Elch2")}, - {USB_DEVICE(0x04fc, 0x0561), DVNM("Flexcam 100")}, - {USB_DEVICE(0x060b, 0xa001), DVNM("Maxell Compact Pc PM3")}, - {USB_DEVICE(0x10fd, 0x7e50), DVNM("FlyCam Usb 100")}, - {USB_DEVICE(0xabcd, 0xcdee), DVNM("Petcam")}, + {USB_DEVICE(0x041e, 0x401a), Rev072A}, + {USB_DEVICE(0x041e, 0x403b), Rev012A}, + {USB_DEVICE(0x0458, 0x7004), Rev072A}, + {USB_DEVICE(0x046d, 0x0928), Rev012A}, + {USB_DEVICE(0x046d, 0x0929), Rev012A}, + {USB_DEVICE(0x046d, 0x092a), Rev012A}, + {USB_DEVICE(0x046d, 0x092b), Rev012A}, + {USB_DEVICE(0x046d, 0x092c), Rev012A}, + {USB_DEVICE(0x046d, 0x092d), Rev012A}, + {USB_DEVICE(0x046d, 0x092e), Rev012A}, + {USB_DEVICE(0x046d, 0x092f), Rev012A}, + {USB_DEVICE(0x04fc, 0x0561), Rev072A}, + {USB_DEVICE(0x060b, 0xa001), Rev072A}, + {USB_DEVICE(0x10fd, 0x7e50), Rev072A}, + {USB_DEVICE(0xabcd, 0xcdee), Rev072A}, {} }; diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c index f6390b49f69..16219cf6a6d 100644 --- a/drivers/media/video/gspca/stk014.c +++ b/drivers/media/video/gspca/stk014.c @@ -545,9 +545,8 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x05e1, 0x0893), DVNM("Syntek DV4000")}, + {USB_DEVICE(0x05e1, 0x0893)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c index 030cb18b355..54efa48bee0 100644 --- a/drivers/media/video/gspca/sunplus.c +++ b/drivers/media/video/gspca/sunplus.c @@ -801,228 +801,29 @@ static int sd_config(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; struct cam *cam; - __u16 vendor; - __u16 product; - __u8 fw; - - vendor = id->idVendor; - product = id->idProduct; - switch (vendor) { - case 0x041e: /* Creative cameras */ -/* switch (product) { */ -/* case 0x400b: */ -/* case 0x4012: */ -/* case 0x4013: */ -/* sd->bridge = BRIDGE_SPCA504C; */ -/* break; */ -/* } */ - break; - case 0x0458: /* Genius KYE cameras */ -/* switch (product) { */ -/* case 0x7006: */ - sd->bridge = BRIDGE_SPCA504B; -/* break; */ -/* } */ - break; - case 0x0461: /* MicroInnovation */ -/* switch (product) { */ -/* case 0x0821: */ - sd->bridge = BRIDGE_SPCA533; -/* break; */ -/* } */ - break; - case 0x046d: /* Logitech Labtec */ - switch (product) { - case 0x0905: - sd->subtype = LogitechClickSmart820; - sd->bridge = BRIDGE_SPCA533; - break; - case 0x0960: - sd->subtype = LogitechClickSmart420; - sd->bridge = BRIDGE_SPCA504C; - break; - } - break; - case 0x0471: /* Philips */ -/* switch (product) { */ -/* case 0x0322: */ - sd->bridge = BRIDGE_SPCA504B; -/* break; */ -/* } */ - break; - case 0x04a5: /* Benq */ - switch (product) { - case 0x3003: - sd->bridge = BRIDGE_SPCA504B; - break; - case 0x3008: - case 0x300a: - sd->bridge = BRIDGE_SPCA533; - break; - } - break; - case 0x04f1: /* JVC */ -/* switch (product) { */ -/* case 0x1001: */ - sd->bridge = BRIDGE_SPCA504B; -/* break; */ -/* } */ - break; - case 0x04fc: /* SunPlus */ - switch (product) { - case 0x500c: - sd->bridge = BRIDGE_SPCA504B; - break; - case 0x504a: + + cam = &gspca_dev->cam; + cam->epaddr = 0x01; + + sd->bridge = id->driver_info >> 8; + sd->subtype = id->driver_info; + + if (sd->subtype == AiptekMiniPenCam13) { /* try to get the firmware as some cam answer 2.0.1.2.2 * and should be a spca504b then overwrite that setting */ - reg_r(dev, 0x20, 0, gspca_dev->usb_buf, 1); - fw = gspca_dev->usb_buf[0]; - if (fw == 1) { - sd->subtype = AiptekMiniPenCam13; - sd->bridge = BRIDGE_SPCA504; - } else if (fw == 2) { - sd->bridge = BRIDGE_SPCA504B; - } else - return -ENODEV; - break; - case 0x504b: - sd->bridge = BRIDGE_SPCA504B; - break; - case 0x5330: - sd->bridge = BRIDGE_SPCA533; - break; - case 0x5360: - sd->bridge = BRIDGE_SPCA536; - break; - case 0xffff: - sd->bridge = BRIDGE_SPCA504B; - break; - } - break; - case 0x052b: /* ?? Megapix */ -/* switch (product) { */ -/* case 0x1513: */ - sd->subtype = MegapixV4; - sd->bridge = BRIDGE_SPCA533; -/* break; */ -/* } */ - break; - case 0x0546: /* Polaroid */ - switch (product) { - case 0x3155: - sd->bridge = BRIDGE_SPCA533; - break; - case 0x3191: - case 0x3273: + reg_r(dev, 0x20, 0, gspca_dev->usb_buf, 1); + switch (gspca_dev->usb_buf[0]) { + case 1: + break; /* (right bridge/subtype) */ + case 2: sd->bridge = BRIDGE_SPCA504B; + sd->subtype = 0; break; + default: + return -ENODEV; } - break; - case 0x055f: /* Mustek cameras */ - switch (product) { - case 0xc211: - sd->bridge = BRIDGE_SPCA536; - break; - case 0xc230: - case 0xc232: - sd->bridge = BRIDGE_SPCA533; - break; - case 0xc360: - sd->bridge = BRIDGE_SPCA536; - break; - case 0xc420: - sd->bridge = BRIDGE_SPCA504; - break; - case 0xc430: - case 0xc440: - sd->bridge = BRIDGE_SPCA533; - break; - case 0xc520: - sd->bridge = BRIDGE_SPCA504; - break; - case 0xc530: - case 0xc540: - case 0xc630: - case 0xc650: - sd->bridge = BRIDGE_SPCA533; - break; - } - break; - case 0x05da: /* Digital Dream cameras */ -/* switch (product) { */ -/* case 0x1018: */ - sd->bridge = BRIDGE_SPCA504B; -/* break; */ -/* } */ - break; - case 0x06d6: /* Trust */ -/* switch (product) { */ -/* case 0x0031: */ - sd->bridge = BRIDGE_SPCA533; /* SPCA533A */ -/* break; */ -/* } */ - break; - case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */ - switch (product) { - case 0x1311: - case 0x1314: - case 0x2211: - case 0x2221: - sd->bridge = BRIDGE_SPCA533; - break; - case 0x3261: - case 0x3281: - sd->bridge = BRIDGE_SPCA536; - break; - } - break; - case 0x08ca: /* Aiptek */ - switch (product) { - case 0x0104: - case 0x0106: - sd->bridge = BRIDGE_SPCA533; - break; - case 0x2008: - sd->bridge = BRIDGE_SPCA504B; - break; - case 0x2010: - sd->bridge = BRIDGE_SPCA533; - break; - case 0x2016: - case 0x2018: - sd->bridge = BRIDGE_SPCA504B; - break; - case 0x2020: - case 0x2022: - sd->bridge = BRIDGE_SPCA533; - break; - case 0x2024: - sd->bridge = BRIDGE_SPCA536; - break; - case 0x2028: - sd->bridge = BRIDGE_SPCA533; - break; - case 0x2040: - case 0x2042: - case 0x2050: - case 0x2060: - sd->bridge = BRIDGE_SPCA536; - break; - } - break; - case 0x0d64: /* SunPlus */ -/* switch (product) { */ -/* case 0x0303: */ - sd->bridge = BRIDGE_SPCA536; -/* break; */ -/* } */ - break; } - cam = &gspca_dev->cam; - cam->epaddr = 0x01; - switch (sd->bridge) { default: /* case BRIDGE_SPCA504B: */ @@ -1577,65 +1378,67 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name +#define BS(bridge, subtype) \ + .driver_info = (BRIDGE_ ## bridge << 8) \ + | (subtype) static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x400b), DVNM("Creative PC-CAM 600")}, - {USB_DEVICE(0x041e, 0x4012), DVNM("PC-Cam350")}, - {USB_DEVICE(0x041e, 0x4013), DVNM("Creative Pccam750")}, - {USB_DEVICE(0x0458, 0x7006), DVNM("Genius Dsc 1.3 Smart")}, - {USB_DEVICE(0x0461, 0x0821), DVNM("Fujifilm MV-1")}, - {USB_DEVICE(0x046d, 0x0905), DVNM("Logitech ClickSmart 820")}, - {USB_DEVICE(0x046d, 0x0960), DVNM("Logitech ClickSmart 420")}, - {USB_DEVICE(0x0471, 0x0322), DVNM("Philips DMVC1300K")}, - {USB_DEVICE(0x04a5, 0x3003), DVNM("Benq DC 1300")}, - {USB_DEVICE(0x04a5, 0x3008), DVNM("Benq DC 1500")}, - {USB_DEVICE(0x04a5, 0x300a), DVNM("Benq DC3410")}, - {USB_DEVICE(0x04f1, 0x1001), DVNM("JVC GC A50")}, - {USB_DEVICE(0x04fc, 0x500c), DVNM("Sunplus CA500C")}, - {USB_DEVICE(0x04fc, 0x504a), DVNM("Aiptek Mini PenCam 1.3")}, - {USB_DEVICE(0x04fc, 0x504b), DVNM("Maxell MaxPocket LE 1.3")}, - {USB_DEVICE(0x04fc, 0x5330), DVNM("Digitrex 2110")}, - {USB_DEVICE(0x04fc, 0x5360), DVNM("Sunplus Generic")}, - {USB_DEVICE(0x04fc, 0xffff), DVNM("Pure DigitalDakota")}, - {USB_DEVICE(0x052b, 0x1513), DVNM("Megapix V4")}, - {USB_DEVICE(0x0546, 0x3155), DVNM("Polaroid PDC3070")}, - {USB_DEVICE(0x0546, 0x3191), DVNM("Polaroid Ion 80")}, - {USB_DEVICE(0x0546, 0x3273), DVNM("Polaroid PDC2030")}, - {USB_DEVICE(0x055f, 0xc211), DVNM("Kowa Bs888e Microcamera")}, - {USB_DEVICE(0x055f, 0xc230), DVNM("Mustek Digicam 330K")}, - {USB_DEVICE(0x055f, 0xc232), DVNM("Mustek MDC3500")}, - {USB_DEVICE(0x055f, 0xc360), DVNM("Mustek DV4000 Mpeg4 ")}, - {USB_DEVICE(0x055f, 0xc420), DVNM("Mustek gSmart Mini 2")}, - {USB_DEVICE(0x055f, 0xc430), DVNM("Mustek Gsmart LCD 2")}, - {USB_DEVICE(0x055f, 0xc440), DVNM("Mustek DV 3000")}, - {USB_DEVICE(0x055f, 0xc520), DVNM("Mustek gSmart Mini 3")}, - {USB_DEVICE(0x055f, 0xc530), DVNM("Mustek Gsmart LCD 3")}, - {USB_DEVICE(0x055f, 0xc540), DVNM("Gsmart D30")}, - {USB_DEVICE(0x055f, 0xc630), DVNM("Mustek MDC4000")}, - {USB_DEVICE(0x055f, 0xc650), DVNM("Mustek MDC5500Z")}, - {USB_DEVICE(0x05da, 0x1018), DVNM("Digital Dream Enigma 1.3")}, - {USB_DEVICE(0x06d6, 0x0031), DVNM("Trust 610 LCD PowerC@m Zoom")}, - {USB_DEVICE(0x0733, 0x1311), DVNM("Digital Dream Epsilon 1.3")}, - {USB_DEVICE(0x0733, 0x1314), DVNM("Mercury 2.1MEG Deluxe Classic Cam")}, - {USB_DEVICE(0x0733, 0x2211), DVNM("Jenoptik jdc 21 LCD")}, - {USB_DEVICE(0x0733, 0x2221), DVNM("Mercury Digital Pro 3.1p")}, - {USB_DEVICE(0x0733, 0x3261), DVNM("Concord 3045 spca536a")}, - {USB_DEVICE(0x0733, 0x3281), DVNM("Cyberpix S550V")}, - {USB_DEVICE(0x08ca, 0x0104), DVNM("Aiptek PocketDVII 1.3")}, - {USB_DEVICE(0x08ca, 0x0106), DVNM("Aiptek Pocket DV3100+")}, - {USB_DEVICE(0x08ca, 0x2008), DVNM("Aiptek Mini PenCam 2 M")}, - {USB_DEVICE(0x08ca, 0x2010), DVNM("Aiptek PocketCam 3M")}, - {USB_DEVICE(0x08ca, 0x2016), DVNM("Aiptek PocketCam 2 Mega")}, - {USB_DEVICE(0x08ca, 0x2018), DVNM("Aiptek Pencam SD 2M")}, - {USB_DEVICE(0x08ca, 0x2020), DVNM("Aiptek Slim 3000F")}, - {USB_DEVICE(0x08ca, 0x2022), DVNM("Aiptek Slim 3200")}, - {USB_DEVICE(0x08ca, 0x2024), DVNM("Aiptek DV3500 Mpeg4 ")}, - {USB_DEVICE(0x08ca, 0x2028), DVNM("Aiptek PocketCam4M")}, - {USB_DEVICE(0x08ca, 0x2040), DVNM("Aiptek PocketDV4100M")}, - {USB_DEVICE(0x08ca, 0x2042), DVNM("Aiptek PocketDV5100")}, - {USB_DEVICE(0x08ca, 0x2050), DVNM("Medion MD 41437")}, - {USB_DEVICE(0x08ca, 0x2060), DVNM("Aiptek PocketDV5300")}, - {USB_DEVICE(0x0d64, 0x0303), DVNM("Sunplus FashionCam DXG")}, + {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)}, + {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)}, + {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)}, + {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)}, + {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)}, + {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)}, + {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)}, + {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)}, + {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)}, + {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)}, + {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)}, + {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)}, + {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)}, + {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)}, + {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)}, + {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)}, + {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)}, + {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)}, + {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)}, + {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)}, + {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)}, + {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)}, + {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)}, + {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)}, + {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)}, + {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)}, + {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)}, + {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)}, + {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)}, + {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)}, + {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)}, + {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)}, + {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)}, + {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)}, + {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)}, + {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)}, + {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)}, + {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)}, + {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)}, + {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)}, + {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)}, + {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)}, + {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)}, + {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c index f7ea9a74272..91b555c34c6 100644 --- a/drivers/media/video/gspca/t613.c +++ b/drivers/media/video/gspca/t613.c @@ -995,9 +995,8 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x17a1, 0x0128), DVNM("XPX Webcam")}, + {USB_DEVICE(0x17a1, 0x0128)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c index b024aca9b10..1ff8ba2f7fe 100644 --- a/drivers/media/video/gspca/tv8532.c +++ b/drivers/media/video/gspca/tv8532.c @@ -620,13 +620,12 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x046d, 0x0920), DVNM("QC Express")}, - {USB_DEVICE(0x046d, 0x0921), DVNM("Labtec Webcam")}, - {USB_DEVICE(0x0545, 0x808b), DVNM("Veo Stingray")}, - {USB_DEVICE(0x0545, 0x8333), DVNM("Veo Stingray")}, - {USB_DEVICE(0x0923, 0x010f), DVNM("ICM532 cams")}, + {USB_DEVICE(0x046d, 0x0920)}, + {USB_DEVICE(0x046d, 0x0921)}, + {USB_DEVICE(0x0545, 0x808b)}, + {USB_DEVICE(0x0545, 0x8333)}, + {USB_DEVICE(0x0923, 0x010f)}, {} }; diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c index 46cff48e629..5cf1af96d5f 100644 --- a/drivers/media/video/gspca/vc032x.c +++ b/drivers/media/video/gspca/vc032x.c @@ -1416,29 +1416,10 @@ static int sd_config(struct gspca_dev *gspca_dev, struct usb_device *dev = gspca_dev->dev; struct cam *cam; int sensor; - __u16 product; - - product = id->idProduct; - sd->bridge = BRIDGE_VC0321; - switch (id->idVendor) { - case 0x0ac8: /* Vimicro z-star */ - switch (product) { - case 0x0323: - sd->bridge = BRIDGE_VC0323; - break; - } - break; - case 0x17ef: /* Lenovo */ -/* switch (product) { */ -/* case 0x4802: * Lenovo MI1310_SOC */ - sd->bridge = BRIDGE_VC0323; -/* break; */ -/* } */ - break; - } cam = &gspca_dev->cam; cam->epaddr = 0x02; + sd->bridge = id->driver_info; if (sd->bridge == BRIDGE_VC0321) { cam->cam_mode = vc0321_mode; cam->nmodes = ARRAY_SIZE(vc0321_mode); @@ -1767,16 +1748,15 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x046d, 0x0892), DVNM("Logitech Orbicam")}, - {USB_DEVICE(0x046d, 0x0896), DVNM("Logitech Orbicam")}, - {USB_DEVICE(0x0ac8, 0x0321), DVNM("Vimicro generic vc0321")}, - {USB_DEVICE(0x0ac8, 0x0323), DVNM("Vimicro Vc0323")}, - {USB_DEVICE(0x0ac8, 0x0328), DVNM("A4Tech PK-130MG")}, - {USB_DEVICE(0x0ac8, 0xc001), DVNM("Sony embedded vimicro")}, - {USB_DEVICE(0x0ac8, 0xc002), DVNM("Sony embedded vimicro")}, - {USB_DEVICE(0x17ef, 0x4802), DVNM("Lenovo Vc0323+MI1310_SOC")}, + {USB_DEVICE(0x046d, 0x0892), BRIDGE_VC0321}, + {USB_DEVICE(0x046d, 0x0896), BRIDGE_VC0321}, + {USB_DEVICE(0x0ac8, 0x0321), BRIDGE_VC0321}, + {USB_DEVICE(0x0ac8, 0x0323), BRIDGE_VC0323}, + {USB_DEVICE(0x0ac8, 0x0328), BRIDGE_VC0321}, + {USB_DEVICE(0x0ac8, 0xc001), BRIDGE_VC0321}, + {USB_DEVICE(0x0ac8, 0xc002), BRIDGE_VC0321}, + {USB_DEVICE(0x17ef, 0x4802), BRIDGE_VC0323}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index acd538da078..257195951a5 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -7012,31 +7012,7 @@ static int sd_config(struct gspca_dev *gspca_dev, /* define some sensors from the vendor/product */ sd->sharpness = 2; - sd->sensor = -1; - switch (id->idVendor) { - case 0x041e: /* Creative */ - switch (id->idProduct) { - case 0x4051: /* zc301 chips */ - case 0x4053: - sd->sensor = SENSOR_TAS5130C_VF0250; - break; - } - break; - case 0x046d: /* Logitech Labtec */ - switch (id->idProduct) { - case 0x08dd: - sd->sensor = SENSOR_MC501CB; - break; - } - break; - case 0x0ac8: /* Vimicro z-star */ - switch (id->idProduct) { - case 0x305b: - sd->sensor = SENSOR_TAS5130C_VF0250; - break; - } - break; - } + sd->sensor = id->driver_info; sensor = zcxx_probeSensor(gspca_dev); if (sensor >= 0) PDEBUG(D_PROBE, "probe sensor -> %02x", sensor); @@ -7522,70 +7498,69 @@ static const struct sd_desc sd_desc = { .querymenu = sd_querymenu, }; -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x041e), DVNM("Creative WebCam Live!")}, + {USB_DEVICE(0x041e, 0x041e)}, #ifndef CONFIG_USB_ZC0301 - {USB_DEVICE(0x041e, 0x4017), DVNM("Creative Webcam Mobile PD1090")}, - {USB_DEVICE(0x041e, 0x401c), DVNM("Creative NX")}, - {USB_DEVICE(0x041e, 0x401e), DVNM("Creative Nx Pro")}, - {USB_DEVICE(0x041e, 0x401f), DVNM("Creative Webcam Notebook PD1171")}, + {USB_DEVICE(0x041e, 0x4017)}, + {USB_DEVICE(0x041e, 0x401c)}, + {USB_DEVICE(0x041e, 0x401e)}, + {USB_DEVICE(0x041e, 0x401f)}, #endif - {USB_DEVICE(0x041e, 0x4029), DVNM("Creative WebCam Vista Pro")}, + {USB_DEVICE(0x041e, 0x4029)}, #ifndef CONFIG_USB_ZC0301 - {USB_DEVICE(0x041e, 0x4034), DVNM("Creative Instant P0620")}, - {USB_DEVICE(0x041e, 0x4035), DVNM("Creative Instant P0620D")}, - {USB_DEVICE(0x041e, 0x4036), DVNM("Creative Live !")}, - {USB_DEVICE(0x041e, 0x403a), DVNM("Creative Nx Pro 2")}, + {USB_DEVICE(0x041e, 0x4034)}, + {USB_DEVICE(0x041e, 0x4035)}, + {USB_DEVICE(0x041e, 0x4036)}, + {USB_DEVICE(0x041e, 0x403a)}, #endif - {USB_DEVICE(0x041e, 0x4051), DVNM("Creative Notebook Pro (VF0250)")}, - {USB_DEVICE(0x041e, 0x4053), DVNM("Creative Live!Cam Video IM")}, + {USB_DEVICE(0x041e, 0x4051), SENSOR_TAS5130C_VF0250}, + {USB_DEVICE(0x041e, 0x4053), SENSOR_TAS5130C_VF0250}, #ifndef CONFIG_USB_ZC0301 - {USB_DEVICE(0x0458, 0x7007), DVNM("Genius VideoCam V2")}, - {USB_DEVICE(0x0458, 0x700c), DVNM("Genius VideoCam V3")}, - {USB_DEVICE(0x0458, 0x700f), DVNM("Genius VideoCam Web V2")}, + {USB_DEVICE(0x0458, 0x7007)}, + {USB_DEVICE(0x0458, 0x700c)}, + {USB_DEVICE(0x0458, 0x700f)}, #endif - {USB_DEVICE(0x0461, 0x0a00), DVNM("MicroInnovation WebCam320")}, - {USB_DEVICE(0x046d, 0x08a0), DVNM("Logitech QC IM")}, - {USB_DEVICE(0x046d, 0x08a1), DVNM("Logitech QC IM 0x08A1 +sound")}, - {USB_DEVICE(0x046d, 0x08a2), DVNM("Labtec Webcam Pro")}, - {USB_DEVICE(0x046d, 0x08a3), DVNM("Logitech QC Chat")}, - {USB_DEVICE(0x046d, 0x08a6), DVNM("Logitech QCim")}, - {USB_DEVICE(0x046d, 0x08a7), DVNM("Logitech QuickCam Image")}, - {USB_DEVICE(0x046d, 0x08a9), DVNM("Logitech Notebook Deluxe")}, - {USB_DEVICE(0x046d, 0x08aa), DVNM("Labtec Webcam Notebook")}, - {USB_DEVICE(0x046d, 0x08ac), DVNM("Logitech QuickCam Cool")}, - {USB_DEVICE(0x046d, 0x08ad), DVNM("Logitech QCCommunicate STX")}, + {USB_DEVICE(0x0461, 0x0a00)}, + {USB_DEVICE(0x046d, 0x08a0)}, + {USB_DEVICE(0x046d, 0x08a1)}, + {USB_DEVICE(0x046d, 0x08a2)}, + {USB_DEVICE(0x046d, 0x08a3)}, + {USB_DEVICE(0x046d, 0x08a6)}, + {USB_DEVICE(0x046d, 0x08a7)}, + {USB_DEVICE(0x046d, 0x08a9)}, + {USB_DEVICE(0x046d, 0x08aa)}, + {USB_DEVICE(0x046d, 0x08ac)}, + {USB_DEVICE(0x046d, 0x08ad)}, #ifndef CONFIG_USB_ZC0301 - {USB_DEVICE(0x046d, 0x08ae), DVNM("Logitech QuickCam for Notebooks")}, + {USB_DEVICE(0x046d, 0x08ae)}, #endif - {USB_DEVICE(0x046d, 0x08af), DVNM("Logitech QuickCam Cool")}, - {USB_DEVICE(0x046d, 0x08b9), DVNM("Logitech QC IM ???")}, - {USB_DEVICE(0x046d, 0x08d7), DVNM("Logitech QCam STX")}, - {USB_DEVICE(0x046d, 0x08d9), DVNM("Logitech QuickCam IM/Connect")}, - {USB_DEVICE(0x046d, 0x08d8), DVNM("Logitech Notebook Deluxe")}, - {USB_DEVICE(0x046d, 0x08da), DVNM("Logitech QuickCam Messenger")}, - {USB_DEVICE(0x046d, 0x08dd), DVNM("Logitech QuickCam for Notebooks")}, - {USB_DEVICE(0x0471, 0x0325), DVNM("Philips SPC 200 NC")}, - {USB_DEVICE(0x0471, 0x0326), DVNM("Philips SPC 300 NC")}, - {USB_DEVICE(0x0471, 0x032d), DVNM("Philips spc210nc")}, - {USB_DEVICE(0x0471, 0x032e), DVNM("Philips spc315nc")}, - {USB_DEVICE(0x055f, 0xc005), DVNM("Mustek Wcam300A")}, + {USB_DEVICE(0x046d, 0x08af)}, + {USB_DEVICE(0x046d, 0x08b9)}, + {USB_DEVICE(0x046d, 0x08d7)}, + {USB_DEVICE(0x046d, 0x08d9)}, + {USB_DEVICE(0x046d, 0x08d8)}, + {USB_DEVICE(0x046d, 0x08da)}, + {USB_DEVICE(0x046d, 0x08dd), SENSOR_MC501CB}, + {USB_DEVICE(0x0471, 0x0325)}, + {USB_DEVICE(0x0471, 0x0326)}, + {USB_DEVICE(0x0471, 0x032d)}, + {USB_DEVICE(0x0471, 0x032e)}, + {USB_DEVICE(0x055f, 0xc005)}, #ifndef CONFIG_USB_ZC0301 - {USB_DEVICE(0x055f, 0xd003), DVNM("Mustek WCam300A")}, - {USB_DEVICE(0x055f, 0xd004), DVNM("Mustek WCam300 AN")}, + {USB_DEVICE(0x055f, 0xd003)}, + {USB_DEVICE(0x055f, 0xd004)}, #endif - {USB_DEVICE(0x0698, 0x2003), DVNM("CTX M730V built in")}, - {USB_DEVICE(0x0ac8, 0x0302), DVNM("Z-star Vimicro zc0302")}, + {USB_DEVICE(0x0698, 0x2003)}, + {USB_DEVICE(0x0ac8, 0x0302)}, #ifndef CONFIG_USB_ZC0301 - {USB_DEVICE(0x0ac8, 0x301b), DVNM("Z-Star zc301b")}, - {USB_DEVICE(0x0ac8, 0x303b), DVNM("Vimicro 0x303b")}, + {USB_DEVICE(0x0ac8, 0x301b)}, + {USB_DEVICE(0x0ac8, 0x303b)}, #endif - {USB_DEVICE(0x0ac8, 0x305b), DVNM("Z-star Vimicro zc0305b")}, + {USB_DEVICE(0x0ac8, 0x305b), SENSOR_TAS5130C_VF0250}, #ifndef CONFIG_USB_ZC0301 - {USB_DEVICE(0x0ac8, 0x307b), DVNM("Z-Star 307b")}, - {USB_DEVICE(0x10fd, 0x0128), DVNM("Typhoon Webshot II 300k 0x0128")}, - {USB_DEVICE(0x10fd, 0x8050), DVNM("Typhoon Webshot II USB 300k")}, + {USB_DEVICE(0x0ac8, 0x307b)}, + {USB_DEVICE(0x10fd, 0x0128)}, + {USB_DEVICE(0x10fd, 0x8050)}, #endif {} /* end of entry */ }; -- cgit v1.2.3 From e546f4bb6d3b320d60c33025597bc8fc31532394 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Sat, 26 Jul 2008 03:43:59 -0300 Subject: V4L/DVB (8515): gspca: Webcam 0c45:6143 added in sonixj. It is an other Pccam168. The .inf says SN9C120B + SP80708, but it should work as SN9C120 + MI0360. Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 46f2cf66d48..33a3df1f691 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -1467,6 +1467,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)}, /* {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x??)}, */ #endif + {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, MI0360, 0x5d)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); -- cgit v1.2.3 From 496cd7e977c73df2c287eaf6d612fc49d6f83dd7 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Sat, 26 Jul 2008 07:49:55 -0300 Subject: V4L/DVB (8517): gspca: Bad sensor for some webcams in zc3xx since 28b8203a830e. '.driver_info = ' forgotten in usb device id table. Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/zc3xx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index 257195951a5..22a994ccb1d 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -7513,8 +7513,8 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x4036)}, {USB_DEVICE(0x041e, 0x403a)}, #endif - {USB_DEVICE(0x041e, 0x4051), SENSOR_TAS5130C_VF0250}, - {USB_DEVICE(0x041e, 0x4053), SENSOR_TAS5130C_VF0250}, + {USB_DEVICE(0x041e, 0x4051), .driver_info = SENSOR_TAS5130C_VF0250}, + {USB_DEVICE(0x041e, 0x4053), .driver_info = SENSOR_TAS5130C_VF0250}, #ifndef CONFIG_USB_ZC0301 {USB_DEVICE(0x0458, 0x7007)}, {USB_DEVICE(0x0458, 0x700c)}, @@ -7540,7 +7540,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x046d, 0x08d9)}, {USB_DEVICE(0x046d, 0x08d8)}, {USB_DEVICE(0x046d, 0x08da)}, - {USB_DEVICE(0x046d, 0x08dd), SENSOR_MC501CB}, + {USB_DEVICE(0x046d, 0x08dd), .driver_info = SENSOR_MC501CB}, {USB_DEVICE(0x0471, 0x0325)}, {USB_DEVICE(0x0471, 0x0326)}, {USB_DEVICE(0x0471, 0x032d)}, @@ -7556,7 +7556,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x0ac8, 0x301b)}, {USB_DEVICE(0x0ac8, 0x303b)}, #endif - {USB_DEVICE(0x0ac8, 0x305b), SENSOR_TAS5130C_VF0250}, + {USB_DEVICE(0x0ac8, 0x305b), .driver_info = SENSOR_TAS5130C_VF0250}, #ifndef CONFIG_USB_ZC0301 {USB_DEVICE(0x0ac8, 0x307b)}, {USB_DEVICE(0x10fd, 0x0128)}, -- cgit v1.2.3 From 1250ac6d4ab716dafe0ac245fd31cd3a7cbc0a98 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Sat, 26 Jul 2008 08:02:47 -0300 Subject: V4L/DVB (8518): gspca: Remove the remaining frame decoding functions from the subdrivers. SPCA505 and SPCA508 added in the pixel formats. Decode functions and associated resources removed in spca505, 506 and 508. The decode routines are now found in the V4L library. Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/spca505.c | 105 ++++++++++-------------------------- drivers/media/video/gspca/spca506.c | 105 ++++++++++-------------------------- drivers/media/video/gspca/spca508.c | 91 +++++++------------------------ 3 files changed, 74 insertions(+), 227 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c index 284d549e4d3..32ffe555606 100644 --- a/drivers/media/video/gspca/spca505.c +++ b/drivers/media/video/gspca/spca505.c @@ -31,10 +31,6 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - int buflen; - unsigned char tmpbuf[640 * 480 * 3 / 2]; /* YYUV per line */ - unsigned char tmpbuf2[640 * 480 * 2]; /* YUYV */ - unsigned char brightness; char subtype; @@ -64,29 +60,29 @@ static struct ctrl sd_ctrls[] = { }; static struct v4l2_pix_format vga_mode[] = { - {160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 160 * 2, - .sizeimage = 160 * 120 * 2, + {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 160 * 3, + .sizeimage = 160 * 120 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 5}, - {176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 176 * 2, - .sizeimage = 176 * 144 * 2, + {176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 176 * 3, + .sizeimage = 176 * 144 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 4}, - {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 320 * 2, - .sizeimage = 320 * 240 * 2, + {320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 320 * 3, + .sizeimage = 320 * 240 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 2}, - {352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 352 * 2, - .sizeimage = 352 * 288 * 2, + {352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 352 * 3, + .sizeimage = 352 * 288 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 1}, - {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 640 * 2, - .sizeimage = 640 * 480 * 2, + {640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 640 * 3, + .sizeimage = 640 * 480 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, }; @@ -760,77 +756,30 @@ static void sd_close(struct gspca_dev *gspca_dev) reg_write(gspca_dev->dev, 0x05, 0x11, 0xf); } -/* convert YYUV per line to YUYV (YUV 4:2:2) */ -static void yyuv_decode(unsigned char *out, - unsigned char *in, - int width, - int height) -{ - unsigned char *Ui, *Vi, *yi, *yi1; - unsigned char *out1; - int i, j; - - yi = in; - for (i = height / 2; --i >= 0; ) { - out1 = out + width * 2; /* next line */ - yi1 = yi + width; - Ui = yi1 + width; - Vi = Ui + width / 2; - for (j = width / 2; --j >= 0; ) { - *out++ = 128 + *yi++; - *out++ = 128 + *Ui; - *out++ = 128 + *yi++; - *out++ = 128 + *Vi; - - *out1++ = 128 + *yi1++; - *out1++ = 128 + *Ui++; - *out1++ = 128 + *yi1++; - *out1++ = 128 + *Vi++; - } - yi += width * 2; - out = out1; - } -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ int len) /* iso packet length */ { - struct sd *sd = (struct sd *) gspca_dev; - switch (data[0]) { case 0: /* start of frame */ - if (gspca_dev->last_packet_type == FIRST_PACKET) { - yyuv_decode(sd->tmpbuf2, sd->tmpbuf, - gspca_dev->width, - gspca_dev->height); - frame = gspca_frame_add(gspca_dev, - LAST_PACKET, - frame, - sd->tmpbuf2, - gspca_dev->width - * gspca_dev->height - * 2); - } - gspca_frame_add(gspca_dev, FIRST_PACKET, frame, - data, 0); + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + data, 0); data += SPCA50X_OFFSET_DATA; len -= SPCA50X_OFFSET_DATA; - if (len > 0) - memcpy(sd->tmpbuf, data, len); - else - len = 0; - sd->buflen = len; - return; + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + data, len); + break; case 0xff: /* drop */ /* gspca_dev->last_packet_type = DISCARD_PACKET; */ - return; + break; + default: + data += 1; + len -= 1; + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + data, len); + break; } - data += 1; - len -= 1; - memcpy(&sd->tmpbuf[sd->buflen], data, len); - sd->buflen += len; } static void setbrightness(struct gspca_dev *gspca_dev) diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c index 2c281a0563e..6fe715c80ad 100644 --- a/drivers/media/video/gspca/spca506.c +++ b/drivers/media/video/gspca/spca506.c @@ -33,10 +33,6 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - int buflen; - __u8 tmpbuf[640 * 480 * 3]; /* YYUV per line */ - __u8 tmpbuf2[640 * 480 * 2]; /* YUYV */ - unsigned char brightness; unsigned char contrast; unsigned char colors; @@ -115,29 +111,29 @@ static struct ctrl sd_ctrls[] = { }; static struct v4l2_pix_format vga_mode[] = { - {160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 160 * 2, - .sizeimage = 160 * 120 * 2, + {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 160 * 3, + .sizeimage = 160 * 120 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 5}, - {176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 176 * 2, - .sizeimage = 176 * 144 * 2, + {176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 176 * 3, + .sizeimage = 176 * 144 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 4}, - {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 320 * 2, - .sizeimage = 320 * 240 * 2, + {320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 320 * 3, + .sizeimage = 320 * 240 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 2}, - {352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 352 * 2, - .sizeimage = 352 * 288 * 2, + {352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 352 * 3, + .sizeimage = 352 * 288 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 1}, - {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 640 * 2, - .sizeimage = 640 * 480 * 2, + {640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 640 * 3, + .sizeimage = 640 * 480 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, }; @@ -572,77 +568,30 @@ static void sd_close(struct gspca_dev *gspca_dev) { } -/* convert YYUV per line to YUYV (YUV 4:2:2) */ -static void yyuv_decode(unsigned char *out, - unsigned char *in, - int width, - int height) -{ - unsigned char *Ui, *Vi, *yi, *yi1; - unsigned char *out1; - int i, j; - - yi = in; - for (i = height / 2; --i >= 0; ) { - out1 = out + width * 2; /* next line */ - yi1 = yi + width; - Ui = yi1 + width; - Vi = Ui + width / 2; - for (j = width / 2; --j >= 0; ) { - *out++ = 128 + *yi++; - *out++ = 128 + *Ui; - *out++ = 128 + *yi++; - *out++ = 128 + *Vi; - - *out1++ = 128 + *yi1++; - *out1++ = 128 + *Ui++; - *out1++ = 128 + *yi1++; - *out1++ = 128 + *Vi++; - } - yi += width * 2; - out = out1; - } -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ int len) /* iso packet length */ { - struct sd *sd = (struct sd *) gspca_dev; - switch (data[0]) { case 0: /* start of frame */ - if (gspca_dev->last_packet_type == FIRST_PACKET) { - yyuv_decode(sd->tmpbuf2, sd->tmpbuf, - gspca_dev->width, - gspca_dev->height); - frame = gspca_frame_add(gspca_dev, - LAST_PACKET, - frame, - sd->tmpbuf2, - gspca_dev->width - * gspca_dev->height - * 2); - } - gspca_frame_add(gspca_dev, FIRST_PACKET, frame, - data, 0); + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + data, 0); data += SPCA50X_OFFSET_DATA; len -= SPCA50X_OFFSET_DATA; - if (len > 0) - memcpy(sd->tmpbuf, data, len); - else - len = 0; - sd->buflen = len; - return; + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + data, len); + break; case 0xff: /* drop */ /* gspca_dev->last_packet_type = DISCARD_PACKET; */ - return; + break; + default: + data += 1; + len -= 1; + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + data, len); + break; } - data += 1; - len -= 1; - memcpy(&sd->tmpbuf[sd->buflen], data, len); - sd->buflen += len; } static void setbrightness(struct gspca_dev *gspca_dev) diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c index af531d62856..4378e966edc 100644 --- a/drivers/media/video/gspca/spca508.c +++ b/drivers/media/video/gspca/spca508.c @@ -30,10 +30,6 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - int buflen; - unsigned char tmpbuf[352 * 288 * 3 / 2]; /* YUVY per line */ - unsigned char tmpbuf2[352 * 288 * 2]; /* YUYV */ - unsigned char brightness; char subtype; @@ -68,23 +64,23 @@ static struct ctrl sd_ctrls[] = { static struct v4l2_pix_format sif_mode[] = { {160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 160 * 2, - .sizeimage = 160 * 120 * 2, + .bytesperline = 160 * 3, + .sizeimage = 160 * 120 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 3}, {176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 176 * 2, - .sizeimage = 176 * 144 * 2, + .bytesperline = 176 * 3, + .sizeimage = 176 * 144 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 2}, {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 320 * 2, - .sizeimage = 320 * 240 * 2, + .bytesperline = 320 * 3, + .sizeimage = 320 * 240 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 1}, {352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 352 * 2, - .sizeimage = 352 * 288 * 2, + .bytesperline = 352 * 3, + .sizeimage = 352 * 288 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, }; @@ -1567,77 +1563,30 @@ static void sd_close(struct gspca_dev *gspca_dev) { } -/* convert YUVY per line to YUYV (YUV 4:2:2) */ -static void yuvy_decode(unsigned char *out, - unsigned char *in, - int width, - int height) -{ - unsigned char *Ui, *Vi, *yi, *yi1; - unsigned char *out1; - int i, j; - - yi = in; - for (i = height / 2; --i >= 0; ) { - out1 = out + width * 2; /* next line */ - Ui = yi + width; - Vi = Ui + width / 2; - yi1 = Vi + width / 2; - for (j = width / 2; --j >= 0; ) { - *out++ = 128 + *yi++; - *out++ = 128 + *Ui; - *out++ = 128 + *yi++; - *out++ = 128 + *Vi; - - *out1++ = 128 + *yi1++; - *out1++ = 128 + *Ui++; - *out1++ = 128 + *yi1++; - *out1++ = 128 + *Vi++; - } - yi += width * 2; - out = out1; - } -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ int len) /* iso packet length */ { - struct sd *sd = (struct sd *) gspca_dev; - switch (data[0]) { case 0: /* start of frame */ - if (gspca_dev->last_packet_type == FIRST_PACKET) { - yuvy_decode(sd->tmpbuf2, sd->tmpbuf, - gspca_dev->width, - gspca_dev->height); - frame = gspca_frame_add(gspca_dev, - LAST_PACKET, - frame, - sd->tmpbuf2, - gspca_dev->width - * gspca_dev->height - * 2); - } - gspca_frame_add(gspca_dev, FIRST_PACKET, frame, - data, 0); + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + data, 0); data += SPCA508_OFFSET_DATA; len -= SPCA508_OFFSET_DATA; - if (len > 0) - memcpy(sd->tmpbuf, data, len); - else - len = 0; - sd->buflen = len; - return; + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + data, len); + break; case 0xff: /* drop */ /* gspca_dev->last_packet_type = DISCARD_PACKET; */ - return; + break; + default: + data += 1; + len -= 1; + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + data, len); + break; } - data += 1; - len -= 1; - memcpy(&sd->tmpbuf[sd->buflen], data, len); - sd->buflen += len; } static void setbrightness(struct gspca_dev *gspca_dev) -- cgit v1.2.3 From 5da162e7e2246851b6d5899688bba5b25a7fea3e Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Sat, 26 Jul 2008 14:17:23 -0300 Subject: V4L/DVB (8519): gspca: Set the specific per webcam information in driver_info for sonixb. Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixb.c | 134 ++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 93d36545659..3db49a854fe 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -58,6 +58,12 @@ struct sd { __u8 reg11; }; +/* flags used in the device id table */ +#define F_GAIN 0x01 /* has gain */ +#define F_AUTO 0x02 /* has autogain */ +#define F_SIF 0x04 /* sif or vga */ +#define F_H18 0x08 /* long (18 b) or short (12 b) frame header */ + #define COMP2 0x8f #define COMP 0xc7 /* 0x87 //0x07 */ #define COMP1 0xc9 /* 0x89 //0x09 */ @@ -751,74 +757,28 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - __u16 product; int sif = 0; /* nctrls depends upon the sensor, so we use a per cam copy */ memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc)); gspca_dev->sd_desc = &sd->sd_desc; - sd->fr_h_sz = 12; /* default size of the frame header */ - sd->sd_desc.nctrls = 2; /* default nb of ctrls */ - product = id->idProduct; -/* switch (id->idVendor) { */ -/* case 0x0c45: * Sonix */ - switch (product) { - case 0x6001: /* SN9C102 */ - case 0x6005: /* SN9C101 */ - case 0x6007: /* SN9C101 */ - sd->sensor = SENSOR_TAS5110; - sd->sensor_has_gain = 1; - sd->sd_desc.nctrls = 4; - sd->sd_desc.dq_callback = do_autogain; - sif = 1; - break; - case 0x6009: /* SN9C101 */ - case 0x600d: /* SN9C101 */ - case 0x6029: /* SN9C101 */ - sd->sensor = SENSOR_PAS106; - sif = 1; - break; - case 0x6011: /* SN9C101 - SN9C101G */ - sd->sensor = SENSOR_OV6650; - sd->sensor_has_gain = 1; - sd->sensor_addr = 0x60; - sd->sd_desc.nctrls = 5; - sd->sd_desc.dq_callback = do_autogain; - sif = 1; - break; - case 0x6019: /* SN9C101 */ - case 0x602c: /* SN9C102 */ - case 0x602e: /* SN9C102 */ - case 0x60b0: /* SN9C103 */ - sd->sensor = SENSOR_OV7630; - sd->sensor_addr = 0x21; - sd->sensor_has_gain = 1; - sd->sd_desc.nctrls = 5; - sd->sd_desc.dq_callback = do_autogain; - if (product == 0x60b0) - sd->fr_h_sz = 18; /* size of frame header */ - break; - case 0x6024: /* SN9C102 */ - case 0x6025: /* SN9C102 */ - sd->sensor = SENSOR_TAS5130CXX; - break; - case 0x6028: /* SN9C102 */ - sd->sensor = SENSOR_PAS202; - break; - case 0x602d: /* SN9C102 */ - sd->sensor = SENSOR_HV7131R; - break; - case 0x60af: /* SN9C103 */ - sd->sensor = SENSOR_PAS202; - sd->fr_h_sz = 18; /* size of frame header (?) */ - break; - } -/* break; */ -/* } */ + /* copy the webcam info from the device id */ + sd->sensor = (id->driver_info >> 24) & 0xff; + if (id->driver_info & (F_GAIN << 16)) + sd->sensor_has_gain = 1; + if (id->driver_info & (F_AUTO << 16)) + sd->sd_desc.dq_callback = do_autogain; + if (id->driver_info & (F_SIF << 16)) + sif = 1; + if (id->driver_info & (F_H18 << 16)) + sd->fr_h_sz = 18; /* size of frame header */ + else + sd->fr_h_sz = 12; + sd->sd_desc.nctrls = (id->driver_info >> 8) & 0xff; + sd->sensor_addr = id->driver_info & 0xff; cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; if (!sif) { cam->cam_mode = vga_mode; @@ -1212,27 +1172,47 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name +#define SFCI(sensor, flags, nctrls, i2c_addr) \ + .driver_info = (SENSOR_ ## sensor << 24) \ + | ((flags) << 16) \ + | ((nctrls) << 8) \ + | (i2c_addr) static __devinitdata struct usb_device_id device_table[] = { #ifndef CONFIG_USB_SN9C102 - {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")}, - {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")}, - {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")}, - {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")}, - {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")}, + {USB_DEVICE(0x0c45, 0x6001), /* SN9C102 */ + SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)}, + {USB_DEVICE(0x0c45, 0x6005), /* SN9C101 */ + SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)}, + {USB_DEVICE(0x0c45, 0x6007), /* SN9C101 */ + SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)}, + {USB_DEVICE(0x0c45, 0x6009), /* SN9C101 */ + SFCI(PAS106, F_SIF, 2, 0)}, + {USB_DEVICE(0x0c45, 0x600d), /* SN9C101 */ + SFCI(PAS106, F_SIF, 2, 0)}, #endif - {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")}, + {USB_DEVICE(0x0c45, 0x6011), /* SN9C101 - SN9C101G */ + SFCI(OV6650, F_GAIN|F_AUTO|F_SIF, 5, 0x60)}, #ifndef CONFIG_USB_SN9C102 - {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")}, - {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")}, - {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")}, - {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")}, - {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")}, - {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")}, - {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")}, - {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")}, - {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")}, - {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")}, + {USB_DEVICE(0x0c45, 0x6019), /* SN9C101 */ + SFCI(OV7630, F_GAIN|F_AUTO|F_SIF, 5, 0x21)}, + {USB_DEVICE(0x0c45, 0x6024), /* SN9C102 */ + SFCI(TAS5130CXX, 0, 2, 0)}, + {USB_DEVICE(0x0c45, 0x6025), /* SN9C102 */ + SFCI(TAS5130CXX, 0, 2, 0)}, + {USB_DEVICE(0x0c45, 0x6028), /* SN9C102 */ + SFCI(PAS202, 0, 2, 0)}, + {USB_DEVICE(0x0c45, 0x6029), /* SN9C101 */ + SFCI(PAS106, F_SIF, 2, 0)}, + {USB_DEVICE(0x0c45, 0x602c), /* SN9C102 */ + SFCI(OV7630, F_GAIN|F_AUTO|F_SIF, 5, 0x21)}, + {USB_DEVICE(0x0c45, 0x602d), /* SN9C102 */ + SFCI(HV7131R, 0, 2, 0)}, + {USB_DEVICE(0x0c45, 0x602e), /* SN9C102 */ + SFCI(OV7630, F_GAIN|F_AUTO|F_SIF, 5, 0x21)}, + {USB_DEVICE(0x0c45, 0x60af), /* SN9C103 */ + SFCI(PAS202, F_H18, 2, 0)}, + {USB_DEVICE(0x0c45, 0x60b0), /* SN9C103 */ + SFCI(OV7630, F_GAIN|F_AUTO|F_SIF|F_H18, 5, 0x21)}, #endif {} }; -- cgit v1.2.3 From 87581aa5f10959224fc7e1a30ac9af53949d0ef2 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Sat, 26 Jul 2008 14:30:01 -0300 Subject: V4L/DVB (8520): gspca: Bad webcam information in some modules since 28b8203a830e. Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/spca500.c | 30 +++++++++++++++--------------- drivers/media/video/gspca/spca501.c | 14 +++++++------- drivers/media/video/gspca/spca505.c | 4 ++-- drivers/media/video/gspca/spca508.c | 14 +++++++------- drivers/media/video/gspca/spca561.c | 30 +++++++++++++++--------------- drivers/media/video/gspca/vc032x.c | 16 ++++++++-------- 6 files changed, 54 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c index 66cf2b684b7..17fe2c2a440 100644 --- a/drivers/media/video/gspca/spca500.c +++ b/drivers/media/video/gspca/spca500.c @@ -1061,21 +1061,21 @@ static struct sd_desc sd_desc = { /* -- module initialisation -- */ static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x040a, 0x0300), KodakEZ200}, - {USB_DEVICE(0x041e, 0x400a), CreativePCCam300}, - {USB_DEVICE(0x046d, 0x0890), LogitechTraveler}, - {USB_DEVICE(0x046d, 0x0900), LogitechClickSmart310}, - {USB_DEVICE(0x046d, 0x0901), LogitechClickSmart510}, - {USB_DEVICE(0x04a5, 0x300c), BenqDC1016}, - {USB_DEVICE(0x04fc, 0x7333), PalmPixDC85}, - {USB_DEVICE(0x055f, 0xc200), MustekGsmart300}, - {USB_DEVICE(0x055f, 0xc220), Gsmartmini}, - {USB_DEVICE(0x06bd, 0x0404), AgfaCl20}, - {USB_DEVICE(0x06be, 0x0800), Optimedia}, - {USB_DEVICE(0x084d, 0x0003), DLinkDSC350}, - {USB_DEVICE(0x08ca, 0x0103), AiptekPocketDV}, - {USB_DEVICE(0x2899, 0x012c), ToptroIndus}, - {USB_DEVICE(0x8086, 0x0630), IntelPocketPCCamera}, + {USB_DEVICE(0x040a, 0x0300), .driver_info = KodakEZ200}, + {USB_DEVICE(0x041e, 0x400a), .driver_info = CreativePCCam300}, + {USB_DEVICE(0x046d, 0x0890), .driver_info = LogitechTraveler}, + {USB_DEVICE(0x046d, 0x0900), .driver_info = LogitechClickSmart310}, + {USB_DEVICE(0x046d, 0x0901), .driver_info = LogitechClickSmart510}, + {USB_DEVICE(0x04a5, 0x300c), .driver_info = BenqDC1016}, + {USB_DEVICE(0x04fc, 0x7333), .driver_info = PalmPixDC85}, + {USB_DEVICE(0x055f, 0xc200), .driver_info = MustekGsmart300}, + {USB_DEVICE(0x055f, 0xc220), .driver_info = Gsmartmini}, + {USB_DEVICE(0x06bd, 0x0404), .driver_info = AgfaCl20}, + {USB_DEVICE(0x06be, 0x0800), .driver_info = Optimedia}, + {USB_DEVICE(0x084d, 0x0003), .driver_info = DLinkDSC350}, + {USB_DEVICE(0x08ca, 0x0103), .driver_info = AiptekPocketDV}, + {USB_DEVICE(0x2899, 0x012c), .driver_info = ToptroIndus}, + {USB_DEVICE(0x8086, 0x0630), .driver_info = IntelPocketPCCamera}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c index a8a460c6eb0..51a3c3429ef 100644 --- a/drivers/media/video/gspca/spca501.c +++ b/drivers/media/video/gspca/spca501.c @@ -2130,13 +2130,13 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x040a, 0x0002), KodakDVC325}, - {USB_DEVICE(0x0497, 0xc001), SmileIntlCamera}, - {USB_DEVICE(0x0506, 0x00df), ThreeComHomeConnectLite}, - {USB_DEVICE(0x0733, 0x0401), IntelCreateAndShare}, - {USB_DEVICE(0x0733, 0x0402), ViewQuestM318B}, - {USB_DEVICE(0x1776, 0x501c), Arowana300KCMOSCamera}, - {USB_DEVICE(0x0000, 0x0000), MystFromOriUnknownCamera}, + {USB_DEVICE(0x040a, 0x0002), .driver_info = KodakDVC325}, + {USB_DEVICE(0x0497, 0xc001), .driver_info = SmileIntlCamera}, + {USB_DEVICE(0x0506, 0x00df), .driver_info = ThreeComHomeConnectLite}, + {USB_DEVICE(0x0733, 0x0401), .driver_info = IntelCreateAndShare}, + {USB_DEVICE(0x0733, 0x0402), .driver_info = ViewQuestM318B}, + {USB_DEVICE(0x1776, 0x501c), .driver_info = Arowana300KCMOSCamera}, + {USB_DEVICE(0x0000, 0x0000), .driver_info = MystFromOriUnknownCamera}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c index 32ffe555606..3c2be80cbd6 100644 --- a/drivers/media/video/gspca/spca505.c +++ b/drivers/media/video/gspca/spca505.c @@ -835,8 +835,8 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x401d), Nxultra}, - {USB_DEVICE(0x0733, 0x0430), IntelPCCameraPro}, + {USB_DEVICE(0x041e, 0x401d), .driver_info = Nxultra}, + {USB_DEVICE(0x0733, 0x0430), .driver_info = IntelPCCameraPro}, /*fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */ {} }; diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c index 4378e966edc..b608a27ad11 100644 --- a/drivers/media/video/gspca/spca508.c +++ b/drivers/media/video/gspca/spca508.c @@ -1643,13 +1643,13 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x0130, 0x0130), HamaUSBSightcam}, - {USB_DEVICE(0x041e, 0x4018), CreativeVista}, - {USB_DEVICE(0x0461, 0x0815), MicroInnovationIC200}, - {USB_DEVICE(0x0733, 0x0110), ViewQuestVQ110}, - {USB_DEVICE(0x0af9, 0x0010), HamaUSBSightcam}, - {USB_DEVICE(0x0af9, 0x0011), HamaUSBSightcam2}, - {USB_DEVICE(0x8086, 0x0110), IntelEasyPCCamera}, + {USB_DEVICE(0x0130, 0x0130), .driver_info = HamaUSBSightcam}, + {USB_DEVICE(0x041e, 0x4018), .driver_info = CreativeVista}, + {USB_DEVICE(0x0461, 0x0815), .driver_info = MicroInnovationIC200}, + {USB_DEVICE(0x0733, 0x0110), .driver_info = ViewQuestVQ110}, + {USB_DEVICE(0x0af9, 0x0010), .driver_info = HamaUSBSightcam}, + {USB_DEVICE(0x0af9, 0x0011), .driver_info = HamaUSBSightcam2}, + {USB_DEVICE(0x8086, 0x0110), .driver_info = IntelEasyPCCamera}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c index 3b46f7dda64..a26174508cb 100644 --- a/drivers/media/video/gspca/spca561.c +++ b/drivers/media/video/gspca/spca561.c @@ -975,21 +975,21 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x401a), Rev072A}, - {USB_DEVICE(0x041e, 0x403b), Rev012A}, - {USB_DEVICE(0x0458, 0x7004), Rev072A}, - {USB_DEVICE(0x046d, 0x0928), Rev012A}, - {USB_DEVICE(0x046d, 0x0929), Rev012A}, - {USB_DEVICE(0x046d, 0x092a), Rev012A}, - {USB_DEVICE(0x046d, 0x092b), Rev012A}, - {USB_DEVICE(0x046d, 0x092c), Rev012A}, - {USB_DEVICE(0x046d, 0x092d), Rev012A}, - {USB_DEVICE(0x046d, 0x092e), Rev012A}, - {USB_DEVICE(0x046d, 0x092f), Rev012A}, - {USB_DEVICE(0x04fc, 0x0561), Rev072A}, - {USB_DEVICE(0x060b, 0xa001), Rev072A}, - {USB_DEVICE(0x10fd, 0x7e50), Rev072A}, - {USB_DEVICE(0xabcd, 0xcdee), Rev072A}, + {USB_DEVICE(0x041e, 0x401a), .driver_info = Rev072A}, + {USB_DEVICE(0x041e, 0x403b), .driver_info = Rev012A}, + {USB_DEVICE(0x0458, 0x7004), .driver_info = Rev072A}, + {USB_DEVICE(0x046d, 0x0928), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x0929), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092a), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092b), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092c), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092d), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092e), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092f), .driver_info = Rev012A}, + {USB_DEVICE(0x04fc, 0x0561), .driver_info = Rev072A}, + {USB_DEVICE(0x060b, 0xa001), .driver_info = Rev072A}, + {USB_DEVICE(0x10fd, 0x7e50), .driver_info = Rev072A}, + {USB_DEVICE(0xabcd, 0xcdee), .driver_info = Rev072A}, {} }; diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c index 5cf1af96d5f..a4221753e1b 100644 --- a/drivers/media/video/gspca/vc032x.c +++ b/drivers/media/video/gspca/vc032x.c @@ -1749,14 +1749,14 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x046d, 0x0892), BRIDGE_VC0321}, - {USB_DEVICE(0x046d, 0x0896), BRIDGE_VC0321}, - {USB_DEVICE(0x0ac8, 0x0321), BRIDGE_VC0321}, - {USB_DEVICE(0x0ac8, 0x0323), BRIDGE_VC0323}, - {USB_DEVICE(0x0ac8, 0x0328), BRIDGE_VC0321}, - {USB_DEVICE(0x0ac8, 0xc001), BRIDGE_VC0321}, - {USB_DEVICE(0x0ac8, 0xc002), BRIDGE_VC0321}, - {USB_DEVICE(0x17ef, 0x4802), BRIDGE_VC0323}, + {USB_DEVICE(0x046d, 0x0892), .driver_info = BRIDGE_VC0321}, + {USB_DEVICE(0x046d, 0x0896), .driver_info = BRIDGE_VC0321}, + {USB_DEVICE(0x0ac8, 0x0321), .driver_info = BRIDGE_VC0321}, + {USB_DEVICE(0x0ac8, 0x0323), .driver_info = BRIDGE_VC0323}, + {USB_DEVICE(0x0ac8, 0x0328), .driver_info = BRIDGE_VC0321}, + {USB_DEVICE(0x0ac8, 0xc001), .driver_info = BRIDGE_VC0321}, + {USB_DEVICE(0x0ac8, 0xc002), .driver_info = BRIDGE_VC0321}, + {USB_DEVICE(0x17ef, 0x4802), .driver_info = BRIDGE_VC0323}, {} }; MODULE_DEVICE_TABLE(usb, device_table); -- cgit v1.2.3 From c52e4f5836cff0a70a25665f475cf5294c9fe5eb Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Sun, 27 Jul 2008 02:56:33 -0300 Subject: V4L/DVB (8521): gspca: Webcams with Sonix bridge and sensor ov7630 are VGA. This fixes a bug introduced in c503a6f8332a (thanks to Hans de Goede). Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 3db49a854fe..e18748c5a14 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -1194,7 +1194,7 @@ static __devinitdata struct usb_device_id device_table[] = { SFCI(OV6650, F_GAIN|F_AUTO|F_SIF, 5, 0x60)}, #ifndef CONFIG_USB_SN9C102 {USB_DEVICE(0x0c45, 0x6019), /* SN9C101 */ - SFCI(OV7630, F_GAIN|F_AUTO|F_SIF, 5, 0x21)}, + SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)}, {USB_DEVICE(0x0c45, 0x6024), /* SN9C102 */ SFCI(TAS5130CXX, 0, 2, 0)}, {USB_DEVICE(0x0c45, 0x6025), /* SN9C102 */ @@ -1204,15 +1204,15 @@ static __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x6029), /* SN9C101 */ SFCI(PAS106, F_SIF, 2, 0)}, {USB_DEVICE(0x0c45, 0x602c), /* SN9C102 */ - SFCI(OV7630, F_GAIN|F_AUTO|F_SIF, 5, 0x21)}, + SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)}, {USB_DEVICE(0x0c45, 0x602d), /* SN9C102 */ SFCI(HV7131R, 0, 2, 0)}, {USB_DEVICE(0x0c45, 0x602e), /* SN9C102 */ - SFCI(OV7630, F_GAIN|F_AUTO|F_SIF, 5, 0x21)}, + SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)}, {USB_DEVICE(0x0c45, 0x60af), /* SN9C103 */ SFCI(PAS202, F_H18, 2, 0)}, {USB_DEVICE(0x0c45, 0x60b0), /* SN9C103 */ - SFCI(OV7630, F_GAIN|F_AUTO|F_SIF|F_H18, 5, 0x21)}, + SFCI(OV7630, F_GAIN|F_AUTO|F_H18, 5, 0x21)}, #endif {} }; -- cgit v1.2.3 From 0ea6bc8d43c9ee3c5384bea184eab020927a5b2c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 26 Jul 2008 08:26:43 -0300 Subject: V4L/DVB (8523): v4l2-dev: remove unused type and type2 field from video_device The type and type2 fields were unused and so could be removed. Instead add a vfl_type field that contains the type of the video device. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_fops.c | 2 +- drivers/media/radio/dsbr100.c | 1 - drivers/media/radio/miropcm20-radio.c | 1 - drivers/media/radio/radio-aimslab.c | 1 - drivers/media/radio/radio-aztech.c | 1 - drivers/media/radio/radio-cadet.c | 1 - drivers/media/radio/radio-gemtek-pci.c | 1 - drivers/media/radio/radio-gemtek.c | 1 - drivers/media/radio/radio-maestro.c | 1 - drivers/media/radio/radio-maxiradio.c | 1 - drivers/media/radio/radio-rtrack2.c | 1 - drivers/media/radio/radio-sf16fmi.c | 1 - drivers/media/radio/radio-sf16fmr2.c | 1 - drivers/media/radio/radio-si470x.c | 1 - drivers/media/radio/radio-terratec.c | 1 - drivers/media/radio/radio-trust.c | 1 - drivers/media/radio/radio-typhoon.c | 1 - drivers/media/radio/radio-zoltrix.c | 1 - drivers/media/video/bt8xx/bttv-driver.c | 23 +++++------------------ drivers/media/video/bw-qcam.c | 1 - drivers/media/video/c-qcam.c | 1 - drivers/media/video/cafe_ccic.c | 2 -- drivers/media/video/cpia.c | 1 - drivers/media/video/cpia2/cpia2_v4l.c | 3 --- drivers/media/video/cx18/cx18-streams.c | 3 --- drivers/media/video/cx23885/cx23885-417.c | 4 ---- drivers/media/video/cx23885/cx23885-video.c | 2 -- drivers/media/video/cx88/cx88-blackbird.c | 2 -- drivers/media/video/cx88/cx88-video.c | 3 --- drivers/media/video/em28xx/em28xx-video.c | 14 +++----------- drivers/media/video/et61x251/et61x251_core.c | 1 - drivers/media/video/gspca/gspca.c | 1 - drivers/media/video/ivtv/ivtv-streams.c | 5 ----- drivers/media/video/meye.c | 1 - drivers/media/video/ov511.c | 1 - drivers/media/video/pms.c | 1 - drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 4 ---- drivers/media/video/pwc/pwc-if.c | 1 - drivers/media/video/s2255drv.c | 1 - drivers/media/video/saa5246a.c | 1 - drivers/media/video/saa5249.c | 1 - drivers/media/video/saa7134/saa7134-core.c | 9 +++------ drivers/media/video/saa7134/saa7134-empress.c | 2 -- drivers/media/video/saa7134/saa7134-video.c | 3 --- drivers/media/video/se401.c | 1 - drivers/media/video/sn9c102/sn9c102_core.c | 1 - drivers/media/video/soc_camera.c | 1 - drivers/media/video/stk-webcam.c | 2 -- drivers/media/video/stradis.c | 1 - drivers/media/video/stv680.c | 1 - drivers/media/video/usbvideo/usbvideo.c | 1 - drivers/media/video/usbvideo/vicam.c | 1 - drivers/media/video/usbvision/usbvision-video.c | 3 --- drivers/media/video/uvc/uvc_driver.c | 2 -- drivers/media/video/v4l2-dev.c | 1 + drivers/media/video/vino.c | 2 -- drivers/media/video/vivi.c | 1 - drivers/media/video/w9966.c | 1 - drivers/media/video/w9968cf.c | 1 - drivers/media/video/zc0301/zc0301_core.c | 1 - drivers/media/video/zoran_driver.c | 2 -- drivers/media/video/zr364xx.c | 1 - 62 files changed, 13 insertions(+), 121 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index 171afe7da6b..cf6a817d505 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -563,7 +563,7 @@ int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev DEB_EE(("dev:%p\n",dev)); - if( VFL_TYPE_GRABBER == (*vid)->type ) { + if ((*vid)->vfl_type == VFL_TYPE_GRABBER) { vv->video_minor = -1; } else { vv->vbi_minor = -1; diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index 0edada6f4b3..1ed88f3abe6 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -463,7 +463,6 @@ static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = { /* V4L2 interface */ static struct video_device dsbr100_videodev_template = { .name = "D-Link DSB-R 100", - .type = VID_TYPE_TUNER, .fops = &usb_dsbr100_fops, .ioctl_ops = &usb_dsbr100_ioctl_ops, .release = video_device_release, diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c index 594e246dfcf..7fd7ee2d32c 100644 --- a/drivers/media/radio/miropcm20-radio.c +++ b/drivers/media/radio/miropcm20-radio.c @@ -230,7 +230,6 @@ static const struct file_operations pcm20_fops = { static struct video_device pcm20_radio = { .name = "Miro PCM 20 radio", - .type = VID_TYPE_TUNER, .fops = &pcm20_fops, .priv = &pcm20_unit }; diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 2540df6dc2c..eba9209b302 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -406,7 +406,6 @@ static const struct v4l2_ioctl_ops rtrack_ioctl_ops = { static struct video_device rtrack_radio = { .name = "RadioTrack radio", - .type = VID_TYPE_TUNER, .fops = &rtrack_fops, .ioctl_ops = &rtrack_ioctl_ops, }; diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c index 537f2f47950..3fe5504428c 100644 --- a/drivers/media/radio/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c @@ -370,7 +370,6 @@ static const struct v4l2_ioctl_ops aztech_ioctl_ops = { static struct video_device aztech_radio = { .name = "Aztech radio", - .type = VID_TYPE_TUNER, .fops = &aztech_fops, .ioctl_ops = &aztech_ioctl_ops, }; diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 362a279f068..6166e726ed7 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -587,7 +587,6 @@ static const struct v4l2_ioctl_ops cadet_ioctl_ops = { static struct video_device cadet_radio = { .name = "Cadet radio", - .type = VID_TYPE_TUNER, .fops = &cadet_fops, .ioctl_ops = &cadet_ioctl_ops, }; diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c index b8c515762b4..36e754e3ffb 100644 --- a/drivers/media/radio/radio-gemtek-pci.c +++ b/drivers/media/radio/radio-gemtek-pci.c @@ -392,7 +392,6 @@ static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = { static struct video_device vdev_template = { .name = "Gemtek PCI Radio", - .type = VID_TYPE_TUNER, .fops = &gemtek_pci_fops, .ioctl_ops = &gemtek_pci_ioctl_ops, }; diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 45b47c1643e..2b1a6221de6 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -570,7 +570,6 @@ static const struct v4l2_ioctl_ops gemtek_ioctl_ops = { static struct video_device gemtek_radio = { .name = "GemTek Radio card", - .type = VID_TYPE_TUNER, .fops = &gemtek_fops, .ioctl_ops = &gemtek_ioctl_ops, }; diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index d074a8c9067..0ada1c697e8 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c @@ -372,7 +372,6 @@ static const struct v4l2_ioctl_ops maestro_ioctl_ops = { static struct video_device maestro_radio = { .name = "Maestro radio", - .type = VID_TYPE_TUNER, .fops = &maestro_fops, .ioctl_ops = &maestro_ioctl_ops, }; diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index 1b909960649..43c75497dc4 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -391,7 +391,6 @@ static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = { static struct video_device maxiradio_radio = { .name = "Maxi Radio FM2000 radio", - .type = VID_TYPE_TUNER, .fops = &maxiradio_fops, .ioctl_ops = &maxiradio_ioctl_ops, }; diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index e065cb16dc5..e2dde080726 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c @@ -312,7 +312,6 @@ static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = { static struct video_device rtrack2_radio = { .name = "RadioTrack II radio", - .type = VID_TYPE_TUNER, .fops = &rtrack2_fops, .ioctl_ops = &rtrack2_ioctl_ops, }; diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 975f8521848..bb5d92f104a 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -312,7 +312,6 @@ static const struct v4l2_ioctl_ops fmi_ioctl_ops = { static struct video_device fmi_radio = { .name = "SF16FMx radio", - .type = VID_TYPE_TUNER, .fops = &fmi_fops, .ioctl_ops = &fmi_ioctl_ops, }; diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index 2786722b494..6290553d24b 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -428,7 +428,6 @@ static const struct v4l2_ioctl_ops fmr2_ioctl_ops = { static struct video_device fmr2_radio = { .name = "SF16FMR2 radio", - .type = VID_TYPE_TUNER, .fops = &fmr2_fops, .ioctl_ops = &fmr2_ioctl_ops, }; diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index 3cf78ccdc58..a4984ff87c9 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c @@ -1609,7 +1609,6 @@ static struct video_device si470x_viddev_template = { .fops = &si470x_fops, .ioctl_ops = &si470x_ioctl_ops, .name = DRIVER_NAME, - .type = VID_TYPE_TUNER, .release = video_device_release, }; diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index b3f669d0691..cefa44fc5ae 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -384,7 +384,6 @@ static const struct v4l2_ioctl_ops terratec_ioctl_ops = { static struct video_device terratec_radio = { .name = "TerraTec ActiveRadio", - .type = VID_TYPE_TUNER, .fops = &terratec_fops, .ioctl_ops = &terratec_ioctl_ops, }; diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index 74aefda868e..d70172d23ed 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c @@ -364,7 +364,6 @@ static const struct v4l2_ioctl_ops trust_ioctl_ops = { static struct video_device trust_radio = { .name = "Trust FM Radio", - .type = VID_TYPE_TUNER, .fops = &trust_fops, .ioctl_ops = &trust_ioctl_ops, }; diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c index 6eb39b7ab75..f8d62cfea77 100644 --- a/drivers/media/radio/radio-typhoon.c +++ b/drivers/media/radio/radio-typhoon.c @@ -362,7 +362,6 @@ static const struct v4l2_ioctl_ops typhoon_ioctl_ops = { static struct video_device typhoon_radio = { .name = "Typhoon Radio", - .type = VID_TYPE_TUNER, .fops = &typhoon_fops, .ioctl_ops = &typhoon_ioctl_ops, }; diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index 4afcb09a4af..9f17a332fa1 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c @@ -425,7 +425,6 @@ static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = { static struct video_device zoltrix_radio = { .name = "Zoltrix Radio Plus", - .type = VID_TYPE_TUNER, .fops = &zoltrix_fops, .ioctl_ops = &zoltrix_ioctl_ops, }; diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index dfa399da587..85bf31ab878 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -4182,8 +4182,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) static struct video_device *vdev_init(struct bttv *btv, const struct video_device *template, - const char *type_name, - const int type) + const char *type_name) { struct video_device *vfd; @@ -4194,7 +4193,6 @@ static struct video_device *vdev_init(struct bttv *btv, vfd->minor = -1; vfd->parent = &btv->c.pci->dev; vfd->release = video_device_release; - vfd->type = type; vfd->debug = bttv_debug; snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)", btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "", @@ -4230,20 +4228,11 @@ static void bttv_unregister_video(struct bttv *btv) /* register video4linux devices */ static int __devinit bttv_register_video(struct bttv *btv) { - int video_type = VID_TYPE_CAPTURE | - VID_TYPE_TUNER | - VID_TYPE_CLIPPING| - VID_TYPE_SCALES; - - if (no_overlay <= 0) { - bttv_video_template.type |= VID_TYPE_OVERLAY; - } else { + if (no_overlay > 0) printk("bttv: Overlay support disabled.\n"); - } /* video */ - btv->video_dev = vdev_init(btv, &bttv_video_template, - "video", video_type); + btv->video_dev = vdev_init(btv, &bttv_video_template, "video"); if (NULL == btv->video_dev) goto err; @@ -4259,8 +4248,7 @@ static int __devinit bttv_register_video(struct bttv *btv) } /* vbi */ - btv->vbi_dev = vdev_init(btv, &bttv_video_template, - "vbi", VID_TYPE_TUNER | VID_TYPE_TELETEXT); + btv->vbi_dev = vdev_init(btv, &bttv_video_template, "vbi"); if (NULL == btv->vbi_dev) goto err; @@ -4272,8 +4260,7 @@ static int __devinit bttv_register_video(struct bttv *btv) if (!btv->has_radio) return 0; /* radio */ - btv->radio_dev = vdev_init(btv, &radio_template, - "radio", VID_TYPE_TUNER); + btv->radio_dev = vdev_init(btv, &radio_template, "radio"); if (NULL == btv->radio_dev) goto err; if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0) diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index ec870c781c0..d3b3268bace 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -908,7 +908,6 @@ static const struct file_operations qcam_fops = { static struct video_device qcam_template= { .name = "Connectix Quickcam", - .type = VID_TYPE_CAPTURE, .fops = &qcam_fops, }; diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c index 62ed8949d46..fe9379b282d 100644 --- a/drivers/media/video/c-qcam.c +++ b/drivers/media/video/c-qcam.c @@ -703,7 +703,6 @@ static const struct file_operations qcam_fops = { static struct video_device qcam_template= { .name = "Colour QuickCam", - .type = VID_TYPE_CAPTURE, .fops = &qcam_fops, }; diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 4bbea458d0c..c149b7d712e 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -1794,8 +1794,6 @@ static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = { static struct video_device cafe_v4l_template = { .name = "cafe", - .type = VFL_TYPE_GRABBER, - .type2 = VID_TYPE_CAPTURE, .minor = -1, /* Get one dynamically */ .tvnorms = V4L2_STD_NTSC_M, .current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */ diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c index 5d2ef48137c..dc8cc6115e2 100644 --- a/drivers/media/video/cpia.c +++ b/drivers/media/video/cpia.c @@ -3800,7 +3800,6 @@ static const struct file_operations cpia_fops = { static struct video_device cpia_template = { .name = "CPiA Camera", - .type = VID_TYPE_CAPTURE, .fops = &cpia_fops, }; diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 4e45de78df5..515c8b57a60 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -1937,9 +1937,6 @@ static const struct file_operations fops_template = { static struct video_device cpia2_template = { /* I could not find any place for the old .initialize initializer?? */ .name= "CPiA2 Camera", - .type= VID_TYPE_CAPTURE, - .type2 = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING, .minor= -1, .fops= &fops_template, .release= video_device_release, diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 210a2416b32..0da57f583bf 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -187,9 +187,6 @@ static int cx18_prep_dev(struct cx18 *cx, int type) return -ENOMEM; } - s->v4l2dev->type = - VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT | - VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER; snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18-%d", cx->num); diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index 9d15d8a353f..8118091568f 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -1731,10 +1731,6 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { static struct video_device cx23885_mpeg_template = { .name = "cx23885", - .type = VID_TYPE_CAPTURE | - VID_TYPE_TUNER | - VID_TYPE_SCALES | - VID_TYPE_MPEG_ENCODER, .fops = &mpeg_fops, .ioctl_ops = &mpeg_ioctl_ops, .minor = -1, diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 308caa2085b..ad2235dab5b 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -1472,7 +1472,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { static struct video_device cx23885_vbi_template; static struct video_device cx23885_video_template = { .name = "cx23885-video", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES, .fops = &video_fops, .minor = -1, .ioctl_ops = &video_ioctl_ops, @@ -1517,7 +1516,6 @@ int cx23885_video_register(struct cx23885_dev *dev) memcpy(&cx23885_vbi_template, &cx23885_video_template, sizeof(cx23885_vbi_template)); strcpy(cx23885_vbi_template.name, "cx23885-vbi"); - cx23885_vbi_template.type = VID_TYPE_TELETEXT|VID_TYPE_TUNER; dev->tvnorm = cx23885_video_template.current_norm; diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 55c35482089..9a1374a38ec 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -1207,8 +1207,6 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { static struct video_device cx8802_mpeg_template = { .name = "cx8802", - .type = VID_TYPE_CAPTURE | VID_TYPE_TUNER | - VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER, .fops = &mpeg_fops, .ioctl_ops = &mpeg_ioctl_ops, .minor = -1, diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 24b403b238d..ef4d56ea002 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1722,7 +1722,6 @@ static struct video_device cx8800_vbi_template; static struct video_device cx8800_video_template = { .name = "cx8800-video", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES, .fops = &video_fops, .minor = -1, .ioctl_ops = &video_ioctl_ops, @@ -1761,7 +1760,6 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { static struct video_device cx8800_radio_template = { .name = "cx8800-radio", - .type = VID_TYPE_TUNER, .fops = &radio_fops, .minor = -1, .ioctl_ops = &radio_ioctl_ops, @@ -1838,7 +1836,6 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, memcpy( &cx8800_vbi_template, &cx8800_video_template, sizeof(cx8800_vbi_template) ); strcpy(cx8800_vbi_template.name,"cx8800-vbi"); - cx8800_vbi_template.type = VID_TYPE_TELETEXT|VID_TYPE_TUNER; /* initialize driver struct */ spin_lock_init(&dev->slock); diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index fcfc7413f74..49ab0629702 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1845,7 +1845,6 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { static struct video_device em28xx_radio_template = { .name = "em28xx-radio", - .type = VID_TYPE_TUNER, .fops = &radio_fops, .ioctl_ops = &radio_ioctl_ops, .minor = -1, @@ -1891,7 +1890,6 @@ EXPORT_SYMBOL(em28xx_unregister_extension); static struct video_device *em28xx_vdev_init(struct em28xx *dev, const struct video_device *template, - const int type, const char *type_name) { struct video_device *vfd; @@ -1903,7 +1901,6 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, vfd->minor = -1; vfd->parent = &dev->udev->dev; vfd->release = video_device_release; - vfd->type = type; vfd->debug = video_debug; snprintf(vfd->name, sizeof(vfd->name), "%s %s", @@ -1981,14 +1978,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, list_add_tail(&dev->devlist, &em28xx_devlist); /* allocate and fill video video_device struct */ - dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, - VID_TYPE_CAPTURE, "video"); + dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); if (NULL == dev->vdev) { em28xx_errdev("cannot allocate video_device.\n"); goto fail_unreg; } - if (dev->tuner_type != TUNER_ABSENT) - dev->vdev->type |= VID_TYPE_TUNER; /* register v4l2 video video_device */ retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, @@ -2000,8 +1994,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, } /* Allocate and fill vbi video_device struct */ - dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, - VFL_TYPE_VBI, "vbi"); + dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, "vbi"); /* register v4l2 vbi video_device */ if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->devno]) < 0) { @@ -2011,8 +2004,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, } if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { - dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, - VFL_TYPE_RADIO, "radio"); + dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, "radio"); if (NULL == dev->radio_dev) { em28xx_errdev("cannot allocate video_device.\n"); goto fail_unreg; diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 3e71ea7bbe2..2d170d101c2 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -2585,7 +2585,6 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) } strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera"); - cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; cam->v4ldev->fops = &et61x251_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index ab053a26023..bc301bae048 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -1691,7 +1691,6 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = { static struct video_device gspca_template = { .name = "gspca main driver", - .type = VID_TYPE_CAPTURE, .fops = &dev_fops, .ioctl_ops = &dev_ioctl_ops, .release = dev_release, /* mandatory */ diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index b883c4e08fb..54d2023b26c 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -208,11 +208,6 @@ static int ivtv_prep_dev(struct ivtv *itv, int type) return -ENOMEM; } - s->v4l2dev->type = VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT | - VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER; - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { - s->v4l2dev->type |= VID_TYPE_MPEG_DECODER; - } snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "ivtv%d %s", itv->num, s->name); diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index f9a6e1e8b4b..7c8ef6ac6c3 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -1721,7 +1721,6 @@ static const struct v4l2_ioctl_ops meye_ioctl_ops = { static struct video_device meye_template = { .name = "meye", - .type = VID_TYPE_CAPTURE, .fops = &meye_fops, .ioctl_ops = &meye_ioctl_ops, .release = video_device_release, diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index 2374ebc084d..9edaca4371d 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c @@ -4667,7 +4667,6 @@ static const struct file_operations ov511_fops = { static struct video_device vdev_template = { .name = "OV511 USB Camera", - .type = VID_TYPE_CAPTURE, .fops = &ov511_fops, .release = video_device_release, .minor = -1, diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c index 8c72e4df85a..00425d74365 100644 --- a/drivers/media/video/pms.c +++ b/drivers/media/video/pms.c @@ -896,7 +896,6 @@ static const struct file_operations pms_fops = { static struct video_device pms_template= { .name = "Mediavision PMS", - .type = VID_TYPE_CAPTURE, .fops = &pms_fops, }; diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index ceb549ac752..00306faeac0 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -1161,10 +1161,6 @@ static const struct file_operations vdev_fops = { static struct video_device vdev_template = { - .type = VID_TYPE_CAPTURE | VID_TYPE_TUNER, - .type2 = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE - | V4L2_CAP_TUNER | V4L2_CAP_AUDIO - | V4L2_CAP_READWRITE), .fops = &vdev_fops, }; diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 436a47caf52..9aee7cb6f79 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -166,7 +166,6 @@ static const struct file_operations pwc_fops = { }; static struct video_device pwc_template = { .name = "Philips Webcam", /* Filled in later */ - .type = VID_TYPE_CAPTURE, .release = video_device_release, .fops = &pwc_fops, .minor = -1, diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c index 92dfb1845ff..b1d09d8e2b8 100644 --- a/drivers/media/video/s2255drv.c +++ b/drivers/media/video/s2255drv.c @@ -1705,7 +1705,6 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = { static struct video_device template = { .name = "s2255v", - .type = VID_TYPE_CAPTURE, .fops = &s2255_fops_v4l, .ioctl_ops = &s2255_ioctl_ops, .minor = -1, diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c index e6a3fa48298..6ee63e69b36 100644 --- a/drivers/media/video/saa5246a.c +++ b/drivers/media/video/saa5246a.c @@ -831,7 +831,6 @@ static const struct file_operations saa_fops = { static struct video_device saa_template = { .name = IF_NAME, - .type = VID_TYPE_TELETEXT, .fops = &saa_fops, .release = video_device_release, .minor = -1, diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c index 6f14619bda4..0d639738d4e 100644 --- a/drivers/media/video/saa5249.c +++ b/drivers/media/video/saa5249.c @@ -712,7 +712,6 @@ static const struct file_operations saa_fops = { static struct video_device saa_template = { .name = IF_NAME, - .type = VID_TYPE_TELETEXT, /*| VID_TYPE_TUNER ?? */ .fops = &saa_fops, }; diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index a404368308a..75d618415f4 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -1008,11 +1008,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, v4l2_prio_init(&dev->prio); /* register v4l devices */ - if (saa7134_no_overlay <= 0) { - saa7134_video_template.type |= VID_TYPE_OVERLAY; - } else { - printk("%s: Overlay support disabled.\n",dev->name); - } + if (saa7134_no_overlay > 0) + printk(KERN_INFO "%s: Overlay support disabled.\n", dev->name); + dev->video_dev = vdev_init(dev,&saa7134_video_template,"video"); err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, video_nr[dev->nr]); @@ -1025,7 +1023,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, dev->name,dev->video_dev->minor & 0x1f); dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi"); - dev->vbi_dev->type = VID_TYPE_TUNER | VID_TYPE_TELETEXT; err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, vbi_nr[dev->nr]); diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index cd52d5be404..c0c5d7509c2 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -439,8 +439,6 @@ static const struct v4l2_ioctl_ops ts_ioctl_ops = { static struct video_device saa7134_empress_template = { .name = "saa7134-empress", - .type = 0 /* FIXME */, - .type2 = 0 /* FIXME */, .fops = &ts_fops, .minor = -1, .ioctl_ops = &ts_ioctl_ops, diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index eb824897416..68c26898186 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -2451,8 +2451,6 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { struct video_device saa7134_video_template = { .name = "saa7134-video", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER | - VID_TYPE_CLIPPING|VID_TYPE_SCALES, .fops = &video_fops, .ioctl_ops = &video_ioctl_ops, .minor = -1, @@ -2462,7 +2460,6 @@ struct video_device saa7134_video_template = { struct video_device saa7134_radio_template = { .name = "saa7134-radio", - .type = VID_TYPE_TUNER, .fops = &radio_fops, .ioctl_ops = &radio_ioctl_ops, .minor = -1, diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c index b4dd60b0f8f..f481277892d 100644 --- a/drivers/media/video/se401.c +++ b/drivers/media/video/se401.c @@ -1231,7 +1231,6 @@ static const struct file_operations se401_fops = { }; static struct video_device se401_template = { .name = "se401 USB camera", - .type = VID_TYPE_CAPTURE, .fops = &se401_fops, }; diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index c68bf0921e9..23408764d0e 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -3309,7 +3309,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) } strcpy(cam->v4ldev->name, "SN9C1xx PC Camera"); - cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; cam->v4ldev->fops = &sn9c102_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 9ff56145258..b6be5ee678b 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -908,7 +908,6 @@ int soc_camera_video_start(struct soc_camera_device *icd) strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); /* Maybe better &ici->dev */ vdev->parent = &icd->dev; - vdev->type = VID_TYPE_CAPTURE; vdev->current_norm = V4L2_STD_UNKNOWN; vdev->fops = &soc_camera_fops; vdev->ioctl_ops = &soc_camera_ioctl_ops; diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index a8a72768ca9..ad36af30e09 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -1359,8 +1359,6 @@ static void stk_v4l_dev_release(struct video_device *vd) static struct video_device stk_v4l_data = { .name = "stkwebcam", - .type = VFL_TYPE_GRABBER, - .type2 = VID_TYPE_CAPTURE, .minor = -1, .tvnorms = V4L2_STD_UNKNOWN, .current_norm = V4L2_STD_UNKNOWN, diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c index 6ace8923b79..276bded06ab 100644 --- a/drivers/media/video/stradis.c +++ b/drivers/media/video/stradis.c @@ -1919,7 +1919,6 @@ static const struct file_operations saa_fops = { /* template for video_device-structure */ static struct video_device saa_template = { .name = "SAA7146A", - .type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY, .fops = &saa_fops, .minor = -1, }; diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index 9053d5a0b1c..56dc3d6b5b2 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -1403,7 +1403,6 @@ static const struct file_operations stv680_fops = { }; static struct video_device stv680_template = { .name = "STV0680 USB camera", - .type = VID_TYPE_CAPTURE, .fops = &stv680_fops, .release = video_device_release, .minor = -1, diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c index 357cee40fb3..bf1bc2f69b0 100644 --- a/drivers/media/video/usbvideo/usbvideo.c +++ b/drivers/media/video/usbvideo/usbvideo.c @@ -952,7 +952,6 @@ static const struct file_operations usbvideo_fops = { .llseek = no_llseek, }; static const struct video_device usbvideo_template = { - .type = VID_TYPE_CAPTURE, .fops = &usbvideo_fops, }; diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c index b8e8fceee52..b7792451a29 100644 --- a/drivers/media/video/usbvideo/vicam.c +++ b/drivers/media/video/usbvideo/vicam.c @@ -793,7 +793,6 @@ static const struct file_operations vicam_fops = { static struct video_device vicam_template = { .name = "ViCam-based USB Camera", - .type = VID_TYPE_CAPTURE, .fops = &vicam_fops, .minor = -1, }; diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index a65e5db0a32..b977116a0dd 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -1405,7 +1405,6 @@ static const struct v4l2_ioctl_ops usbvision_ioctl_ops = { }; static struct video_device usbvision_video_template = { - .type = VID_TYPE_TUNER | VID_TYPE_CAPTURE, .fops = &usbvision_fops, .ioctl_ops = &usbvision_ioctl_ops, .name = "usbvision-video", @@ -1443,7 +1442,6 @@ static const struct v4l2_ioctl_ops usbvision_radio_ioctl_ops = { }; static struct video_device usbvision_radio_template = { - .type = VID_TYPE_TUNER, .fops = &usbvision_radio_fops, .name = "usbvision-radio", .release = video_device_release, @@ -1466,7 +1464,6 @@ static const struct file_operations usbvision_vbi_fops = { static struct video_device usbvision_vbi_template= { - .type = VID_TYPE_TUNER, .fops = &usbvision_vbi_fops, .release = video_device_release, .name = "usbvision-vbi", diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 79d6821c474..b3c4d75e849 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -1459,8 +1459,6 @@ static int uvc_register_video(struct uvc_device *dev) * get another one. */ vdev->parent = &dev->intf->dev; - vdev->type = 0; - vdev->type2 = 0; vdev->minor = -1; vdev->fops = &uvc_fops; vdev->release = video_device_release; diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 88eeee1d8ba..556615fe93d 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -302,6 +302,7 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, } } video_device[i] = vfd; + vfd->vfl_type = type; vfd->minor = i; ret = get_index(vfd, index); diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index f0fcb008b72..3989b0eded2 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -4385,8 +4385,6 @@ static const struct file_operations vino_fops = { static struct video_device v4l_device_template = { .name = "NOT SET", - /*.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE | */ - /* VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY */ .fops = &vino_fops, .minor = -1, }; diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 639210e5264..3518af071a2 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1092,7 +1092,6 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = { static struct video_device vivi_template = { .name = "vivi", - .type = VID_TYPE_CAPTURE, .fops = &vivi_fops, .ioctl_ops = &vivi_ioctl_ops, .minor = -1, diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c index 925b4e7b557..9402f40095b 100644 --- a/drivers/media/video/w9966.c +++ b/drivers/media/video/w9966.c @@ -197,7 +197,6 @@ static const struct file_operations w9966_fops = { }; static struct video_device w9966_template = { .name = W9966_DRIVERNAME, - .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES, .fops = &w9966_fops, }; diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 8f665953c80..168baabe465 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -3550,7 +3550,6 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) } strcpy(cam->v4ldev->name, symbolic(camlist, mod_id)); - cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; cam->v4ldev->fops = &w9968cf_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c index 0978a7e946b..550ce7bd5c8 100644 --- a/drivers/media/video/zc0301/zc0301_core.c +++ b/drivers/media/video/zc0301/zc0301_core.c @@ -1985,7 +1985,6 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) } strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera"); - cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; cam->v4ldev->fops = &zc0301_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index 3ca58221d5a..ec6f59674b1 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -4644,8 +4644,6 @@ static const struct file_operations zoran_fops = { struct video_device zoran_template __devinitdata = { .name = ZORAN_NAME, - .type = ZORAN_VID_TYPE, - .type2 = ZORAN_V4L2_VID_FLAGS, .fops = &zoran_fops, .release = &zoran_vdev_release, .minor = -1 diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c index 36ba36a5e2e..18d1c4ba79f 100644 --- a/drivers/media/video/zr364xx.c +++ b/drivers/media/video/zr364xx.c @@ -780,7 +780,6 @@ static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = { static struct video_device zr364xx_template = { .name = DRIVER_DESC, - .type = VID_TYPE_CAPTURE, .fops = &zr364xx_fops, .ioctl_ops = &zr364xx_ioctl_ops, .release = video_device_release, -- cgit v1.2.3 From de1e575db21a341b77b296af7dd87f163ebf6020 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 26 Jul 2008 08:37:58 -0300 Subject: V4L/DVB (8525): fix a few assorted spelling mistakes. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-vmalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index a868b7ed75f..be65a2fb397 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -203,7 +203,7 @@ static int __videobuf_iolock (struct videobuf_queue* q, return 0; /* FIXME: to properly support USERPTR, remap should occur. - The code bellow won't work, since mem->vma = NULL + The code below won't work, since mem->vma = NULL */ /* Try to remap memory */ rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0); -- cgit v1.2.3 From f796804f01429b832e1e734c54f0f535b322c665 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 26 Jul 2008 09:16:29 -0300 Subject: V4L/DVB (8526): saa7146: fix VIDIOC_ENUM_FMT VIDIOC_ENUM_FMT should keep the index and type fields. Instead, type was zeroed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_video.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index a5e62750eea..acaddc15dad 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -958,21 +958,18 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int case VIDIOC_ENUM_FMT: { struct v4l2_fmtdesc *f = arg; - int index; switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - case V4L2_BUF_TYPE_VIDEO_OVERLAY: { - index = f->index; - if (index < 0 || index >= NUM_FORMATS) { + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (f->index >= NUM_FORMATS) return -EINVAL; - } - memset(f,0,sizeof(*f)); - f->index = index; - strlcpy((char *)f->description,formats[index].name,sizeof(f->description)); - f->pixelformat = formats[index].pixelformat; + strlcpy((char *)f->description, formats[f->index].name, + sizeof(f->description)); + f->pixelformat = formats[f->index].pixelformat; + f->flags = 0; + memset(f->reserved, 0, sizeof(f->reserved)); break; - } default: return -EINVAL; } -- cgit v1.2.3 From 2a83e4d5e40fd8eda3c04a5847f0876a4be9d45b Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 7 Jul 2008 18:20:58 -0300 Subject: V4L/DVB (8528): add support for MaxLinear MxL5007T silicon tuner Signed-off-by: Michael Krufky Signed-off-by: Asaf Fishov Signed-off-by: Charles Kim Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/Kconfig | 7 + drivers/media/common/tuners/Makefile | 1 + drivers/media/common/tuners/mxl5007t.c | 1017 ++++++++++++++++++++++++++++++++ drivers/media/common/tuners/mxl5007t.h | 105 ++++ 4 files changed, 1130 insertions(+) create mode 100644 drivers/media/common/tuners/mxl5007t.c create mode 100644 drivers/media/common/tuners/mxl5007t.h (limited to 'drivers') diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig index 850d5689b14..8d93ba85736 100644 --- a/drivers/media/common/tuners/Kconfig +++ b/drivers/media/common/tuners/Kconfig @@ -162,4 +162,11 @@ config MEDIA_TUNER_MXL5005S help A driver for the silicon tuner MXL5005S from MaxLinear. +config MEDIA_TUNER_MXL5007T + tristate "MaxLinear MxL5007T silicon tuner" + depends on VIDEO_MEDIA && I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon tuner MxL5007T from MaxLinear. + endif # MEDIA_TUNER_CUSTOMIZE diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile index 55f7e670629..4dfbe5b8264 100644 --- a/drivers/media/common/tuners/Makefile +++ b/drivers/media/common/tuners/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o +obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/common/tuners/mxl5007t.c new file mode 100644 index 00000000000..80cfa9ba1dc --- /dev/null +++ b/drivers/media/common/tuners/mxl5007t.c @@ -0,0 +1,1017 @@ +/* + * mxl5007t.c - driver for the MaxLinear MxL5007T silicon tuner + * + * Copyright (C) 2008 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include "tuner-i2c.h" +#include "mxl5007t.h" + +static DEFINE_MUTEX(mxl5007t_list_mutex); +static LIST_HEAD(hybrid_tuner_instance_list); + +static int mxl5007t_debug; +module_param_named(debug, mxl5007t_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debug level"); + +/* ------------------------------------------------------------------------- */ + +#define mxl_printk(kern, fmt, arg...) \ + printk(kern "%s: " fmt "\n", __func__, ##arg) + +#define mxl_err(fmt, arg...) \ + mxl_printk(KERN_ERR, "%d: " fmt, __LINE__, ##arg) + +#define mxl_warn(fmt, arg...) \ + mxl_printk(KERN_WARNING, fmt, ##arg) + +#define mxl_info(fmt, arg...) \ + mxl_printk(KERN_INFO, fmt, ##arg) + +#define mxl_debug(fmt, arg...) \ +({ \ + if (mxl5007t_debug) \ + mxl_printk(KERN_DEBUG, fmt, ##arg); \ +}) + +#define mxl_fail(ret) \ +({ \ + int __ret; \ + __ret = (ret < 0); \ + if (__ret) \ + mxl_printk(KERN_ERR, "error %d on line %d", \ + ret, __LINE__); \ + __ret; \ +}) + +/* ------------------------------------------------------------------------- */ + +#define MHz 1000000 + +enum mxl5007t_mode { + MxL_MODE_OTA_DVBT_ATSC = 0, + MxL_MODE_OTA_NTSC_PAL_GH = 1, + MxL_MODE_OTA_PAL_IB = 2, + MxL_MODE_OTA_PAL_D_SECAM_KL = 3, + MxL_MODE_OTA_ISDBT = 4, + MxL_MODE_CABLE_DIGITAL = 0x10, + MxL_MODE_CABLE_NTSC_PAL_GH = 0x11, + MxL_MODE_CABLE_PAL_IB = 0x12, + MxL_MODE_CABLE_PAL_D_SECAM_KL = 0x13, + MxL_MODE_CABLE_SCTE40 = 0x14, +}; + +enum mxl5007t_chip_version { + MxL_UNKNOWN_ID = 0x00, + MxL_5007_V1_F1 = 0x11, + MxL_5007_V1_F2 = 0x12, + MxL_5007_V2_100_F1 = 0x21, + MxL_5007_V2_100_F2 = 0x22, + MxL_5007_V2_200_F1 = 0x23, + MxL_5007_V2_200_F2 = 0x24, +}; + +struct reg_pair_t { + u8 reg; + u8 val; +}; + +/* ------------------------------------------------------------------------- */ + +static struct reg_pair_t init_tab[] = { + { 0x0b, 0x44 }, /* XTAL */ + { 0x0c, 0x60 }, /* IF */ + { 0x10, 0x00 }, /* MISC */ + { 0x12, 0xca }, /* IDAC */ + { 0x16, 0x90 }, /* MODE */ + { 0x32, 0x38 }, /* MODE Analog/Digital */ + { 0xd8, 0x18 }, /* CLK_OUT_ENABLE */ + { 0x2c, 0x34 }, /* OVERRIDE */ + { 0x4d, 0x40 }, /* OVERRIDE */ + { 0x7f, 0x02 }, /* OVERRIDE */ + { 0x9a, 0x52 }, /* OVERRIDE */ + { 0x48, 0x5a }, /* OVERRIDE */ + { 0x76, 0x1a }, /* OVERRIDE */ + { 0x6a, 0x48 }, /* OVERRIDE */ + { 0x64, 0x28 }, /* OVERRIDE */ + { 0x66, 0xe6 }, /* OVERRIDE */ + { 0x35, 0x0e }, /* OVERRIDE */ + { 0x7e, 0x01 }, /* OVERRIDE */ + { 0x83, 0x00 }, /* OVERRIDE */ + { 0x04, 0x0b }, /* OVERRIDE */ + { 0x05, 0x01 }, /* TOP_MASTER_ENABLE */ + { 0, 0 } +}; + +static struct reg_pair_t init_tab_cable[] = { + { 0x0b, 0x44 }, /* XTAL */ + { 0x0c, 0x60 }, /* IF */ + { 0x10, 0x00 }, /* MISC */ + { 0x12, 0xca }, /* IDAC */ + { 0x16, 0x90 }, /* MODE */ + { 0x32, 0x38 }, /* MODE A/D */ + { 0x71, 0x3f }, /* TOP1 */ + { 0x72, 0x3f }, /* TOP2 */ + { 0x74, 0x3f }, /* TOP3 */ + { 0xd8, 0x18 }, /* CLK_OUT_ENABLE */ + { 0x2c, 0x34 }, /* OVERRIDE */ + { 0x4d, 0x40 }, /* OVERRIDE */ + { 0x7f, 0x02 }, /* OVERRIDE */ + { 0x9a, 0x52 }, /* OVERRIDE */ + { 0x48, 0x5a }, /* OVERRIDE */ + { 0x76, 0x1a }, /* OVERRIDE */ + { 0x6a, 0x48 }, /* OVERRIDE */ + { 0x64, 0x28 }, /* OVERRIDE */ + { 0x66, 0xe6 }, /* OVERRIDE */ + { 0x35, 0x0e }, /* OVERRIDE */ + { 0x7e, 0x01 }, /* OVERRIDE */ + { 0x04, 0x0b }, /* OVERRIDE */ + { 0x68, 0xb4 }, /* OVERRIDE */ + { 0x36, 0x00 }, /* OVERRIDE */ + { 0x05, 0x01 }, /* TOP_MASTER_ENABLE */ + { 0, 0 } +}; + +/* ------------------------------------------------------------------------- */ + +static struct reg_pair_t reg_pair_rftune[] = { + { 0x11, 0x00 }, /* abort tune */ + { 0x13, 0x15 }, + { 0x14, 0x40 }, + { 0x15, 0x0e }, + { 0x11, 0x02 }, /* start tune */ + { 0, 0 } +}; + +/* ------------------------------------------------------------------------- */ + +struct mxl5007t_state { + struct list_head hybrid_tuner_instance_list; + struct tuner_i2c_props i2c_props; + + struct mutex lock; + + struct mxl5007t_config *config; + + enum mxl5007t_chip_version chip_id; + + struct reg_pair_t tab_init[ARRAY_SIZE(init_tab)]; + struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)]; + struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)]; + + u32 frequency; + u32 bandwidth; +}; + +/* ------------------------------------------------------------------------- */ + +/* called by _init and _rftun to manipulate the register arrays */ + +static void set_reg_bits(struct reg_pair_t *reg_pair, u8 reg, u8 mask, u8 val) +{ + unsigned int i = 0; + + while (reg_pair[i].reg || reg_pair[i].val) { + if (reg_pair[i].reg == reg) { + reg_pair[i].val &= ~mask; + reg_pair[i].val |= val; + } + i++; + + } + return; +} + +static void copy_reg_bits(struct reg_pair_t *reg_pair1, + struct reg_pair_t *reg_pair2) +{ + unsigned int i, j; + + i = j = 0; + + while (reg_pair1[i].reg || reg_pair1[i].val) { + while (reg_pair2[j].reg || reg_pair2[j].reg) { + if (reg_pair1[i].reg != reg_pair2[j].reg) { + j++; + continue; + } + reg_pair2[j].val = reg_pair1[i].val; + break; + } + i++; + } + return; +} + +/* ------------------------------------------------------------------------- */ + +static void mxl5007t_set_mode_bits(struct mxl5007t_state *state, + enum mxl5007t_mode mode, + s32 if_diff_out_level) +{ + switch (mode) { + case MxL_MODE_OTA_DVBT_ATSC: + set_reg_bits(state->tab_init, 0x32, 0x0f, 0x06); + set_reg_bits(state->tab_init, 0x35, 0xff, 0x0e); + break; + case MxL_MODE_OTA_ISDBT: + set_reg_bits(state->tab_init, 0x32, 0x0f, 0x06); + set_reg_bits(state->tab_init, 0x35, 0xff, 0x12); + break; + case MxL_MODE_OTA_NTSC_PAL_GH: + set_reg_bits(state->tab_init, 0x16, 0x70, 0x00); + set_reg_bits(state->tab_init, 0x32, 0xff, 0x85); + break; + case MxL_MODE_OTA_PAL_IB: + set_reg_bits(state->tab_init, 0x16, 0x70, 0x10); + set_reg_bits(state->tab_init, 0x32, 0xff, 0x85); + break; + case MxL_MODE_OTA_PAL_D_SECAM_KL: + set_reg_bits(state->tab_init, 0x16, 0x70, 0x20); + set_reg_bits(state->tab_init, 0x32, 0xff, 0x85); + break; + case MxL_MODE_CABLE_DIGITAL: + set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01); + set_reg_bits(state->tab_init_cable, 0x72, 0xff, + 8 - if_diff_out_level); + set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17); + break; + case MxL_MODE_CABLE_NTSC_PAL_GH: + set_reg_bits(state->tab_init, 0x16, 0x70, 0x00); + set_reg_bits(state->tab_init, 0x32, 0xff, 0x85); + set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01); + set_reg_bits(state->tab_init_cable, 0x72, 0xff, + 8 - if_diff_out_level); + set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17); + break; + case MxL_MODE_CABLE_PAL_IB: + set_reg_bits(state->tab_init, 0x16, 0x70, 0x10); + set_reg_bits(state->tab_init, 0x32, 0xff, 0x85); + set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01); + set_reg_bits(state->tab_init_cable, 0x72, 0xff, + 8 - if_diff_out_level); + set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17); + break; + case MxL_MODE_CABLE_PAL_D_SECAM_KL: + set_reg_bits(state->tab_init, 0x16, 0x70, 0x20); + set_reg_bits(state->tab_init, 0x32, 0xff, 0x85); + set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01); + set_reg_bits(state->tab_init_cable, 0x72, 0xff, + 8 - if_diff_out_level); + set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17); + break; + case MxL_MODE_CABLE_SCTE40: + set_reg_bits(state->tab_init_cable, 0x36, 0xff, 0x08); + set_reg_bits(state->tab_init_cable, 0x68, 0xff, 0xbc); + set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01); + set_reg_bits(state->tab_init_cable, 0x72, 0xff, + 8 - if_diff_out_level); + set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17); + break; + default: + mxl_fail(-EINVAL); + } + return; +} + +static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state, + enum mxl5007t_if_freq if_freq, + int invert_if) +{ + u8 val; + + switch (if_freq) { + case MxL_IF_4_MHZ: + val = 0x00; + break; + case MxL_IF_4_5_MHZ: + val = 0x20; + break; + case MxL_IF_4_57_MHZ: + val = 0x30; + break; + case MxL_IF_5_MHZ: + val = 0x40; + break; + case MxL_IF_5_38_MHZ: + val = 0x50; + break; + case MxL_IF_6_MHZ: + val = 0x60; + break; + case MxL_IF_6_28_MHZ: + val = 0x70; + break; + case MxL_IF_9_1915_MHZ: + val = 0x80; + break; + case MxL_IF_35_25_MHZ: + val = 0x90; + break; + case MxL_IF_36_15_MHZ: + val = 0xa0; + break; + case MxL_IF_44_MHZ: + val = 0xb0; + break; + default: + mxl_fail(-EINVAL); + return; + } + set_reg_bits(state->tab_init, 0x0c, 0xf0, val); + + /* set inverted IF or normal IF */ + set_reg_bits(state->tab_init, 0x0c, 0x08, invert_if ? 0x08 : 0x00); + + return; +} + +static void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state, + enum mxl5007t_xtal_freq xtal_freq) +{ + u8 val; + + switch (xtal_freq) { + case MxL_XTAL_16_MHZ: + val = 0x00; /* select xtal freq & Ref Freq */ + break; + case MxL_XTAL_20_MHZ: + val = 0x11; + break; + case MxL_XTAL_20_25_MHZ: + val = 0x22; + break; + case MxL_XTAL_20_48_MHZ: + val = 0x33; + break; + case MxL_XTAL_24_MHZ: + val = 0x44; + break; + case MxL_XTAL_25_MHZ: + val = 0x55; + break; + case MxL_XTAL_25_14_MHZ: + val = 0x66; + break; + case MxL_XTAL_27_MHZ: + val = 0x77; + break; + case MxL_XTAL_28_8_MHZ: + val = 0x88; + break; + case MxL_XTAL_32_MHZ: + val = 0x99; + break; + case MxL_XTAL_40_MHZ: + val = 0xaa; + break; + case MxL_XTAL_44_MHZ: + val = 0xbb; + break; + case MxL_XTAL_48_MHZ: + val = 0xcc; + break; + case MxL_XTAL_49_3811_MHZ: + val = 0xdd; + break; + default: + mxl_fail(-EINVAL); + return; + } + set_reg_bits(state->tab_init, 0x0b, 0xff, val); + + return; +} + +static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state, + enum mxl5007t_mode mode) +{ + struct mxl5007t_config *cfg = state->config; + + memcpy(&state->tab_init, &init_tab, sizeof(init_tab)); + memcpy(&state->tab_init_cable, &init_tab_cable, sizeof(init_tab_cable)); + + mxl5007t_set_mode_bits(state, mode, cfg->if_diff_out_level); + mxl5007t_set_if_freq_bits(state, cfg->if_freq_hz, cfg->invert_if); + mxl5007t_set_xtal_freq_bits(state, cfg->xtal_freq_hz); + + set_reg_bits(state->tab_init, 0x10, 0x40, cfg->loop_thru_enable << 6); + + set_reg_bits(state->tab_init, 0xd8, 0x08, cfg->clk_out_enable << 3); + + set_reg_bits(state->tab_init, 0x10, 0x07, cfg->clk_out_amp); + + /* set IDAC to automatic mode control by AGC */ + set_reg_bits(state->tab_init, 0x12, 0x80, 0x00); + + if (mode >= MxL_MODE_CABLE_DIGITAL) { + copy_reg_bits(state->tab_init, state->tab_init_cable); + return state->tab_init_cable; + } else + return state->tab_init; +} + +/* ------------------------------------------------------------------------- */ + +enum mxl5007t_bw_mhz { + MxL_BW_6MHz = 6, + MxL_BW_7MHz = 7, + MxL_BW_8MHz = 8, +}; + +static void mxl5007t_set_bw_bits(struct mxl5007t_state *state, + enum mxl5007t_bw_mhz bw) +{ + u8 val; + + switch (bw) { + case MxL_BW_6MHz: + val = 0x15; /* set DIG_MODEINDEX, DIG_MODEINDEX_A, + * and DIG_MODEINDEX_CSF */ + break; + case MxL_BW_7MHz: + val = 0x21; + break; + case MxL_BW_8MHz: + val = 0x3f; + break; + default: + mxl_fail(-EINVAL); + return; + } + set_reg_bits(state->tab_rftune, 0x13, 0x3f, val); + + return; +} + +static struct +reg_pair_t *mxl5007t_calc_rf_tune_regs(struct mxl5007t_state *state, + u32 rf_freq, enum mxl5007t_bw_mhz bw) +{ + u32 dig_rf_freq = 0; + u32 temp; + u32 frac_divider = 1000000; + unsigned int i; + + memcpy(&state->tab_rftune, ®_pair_rftune, sizeof(reg_pair_rftune)); + + mxl5007t_set_bw_bits(state, bw); + + /* Convert RF frequency into 16 bits => + * 10 bit integer (MHz) + 6 bit fraction */ + dig_rf_freq = rf_freq / MHz; + + temp = rf_freq % MHz; + + for (i = 0; i < 6; i++) { + dig_rf_freq <<= 1; + frac_divider /= 2; + if (temp > frac_divider) { + temp -= frac_divider; + dig_rf_freq++; + } + } + + /* add to have shift center point by 7.8124 kHz */ + if (temp > 7812) + dig_rf_freq++; + + set_reg_bits(state->tab_rftune, 0x14, 0xff, (u8)dig_rf_freq); + set_reg_bits(state->tab_rftune, 0x15, 0xff, (u8)(dig_rf_freq >> 8)); + + return state->tab_rftune; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_write_reg(struct mxl5007t_state *state, u8 reg, u8 val) +{ + u8 buf[] = { reg, val }; + struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0, + .buf = buf, .len = 2 }; + int ret; + + ret = i2c_transfer(state->i2c_props.adap, &msg, 1); + if (ret != 1) { + mxl_err("failed!"); + return -EREMOTEIO; + } + return 0; +} + +static int mxl5007t_write_regs(struct mxl5007t_state *state, + struct reg_pair_t *reg_pair) +{ + unsigned int i = 0; + int ret = 0; + + while ((ret == 0) && (reg_pair[i].reg || reg_pair[i].val)) { + ret = mxl5007t_write_reg(state, + reg_pair[i].reg, reg_pair[i].val); + i++; + } + return ret; +} + +static int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val) +{ + struct i2c_msg msg[] = { + { .addr = state->i2c_props.addr, .flags = 0, + .buf = ®, .len = 1 }, + { .addr = state->i2c_props.addr, .flags = I2C_M_RD, + .buf = val, .len = 1 }, + }; + int ret; + + ret = i2c_transfer(state->i2c_props.adap, msg, 2); + if (ret != 2) { + mxl_err("failed!"); + return -EREMOTEIO; + } + return 0; +} + +static int mxl5007t_soft_reset(struct mxl5007t_state *state) +{ + u8 d = 0xff; + struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0, + .buf = &d, .len = 1 }; + + int ret = i2c_transfer(state->i2c_props.adap, &msg, 1); + + if (ret != 1) { + mxl_err("failed!"); + return -EREMOTEIO; + } + return 0; +} + +static int mxl5007t_tuner_init(struct mxl5007t_state *state, + enum mxl5007t_mode mode) +{ + struct reg_pair_t *init_regs; + int ret; + + ret = mxl5007t_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + + /* calculate initialization reg array */ + init_regs = mxl5007t_calc_init_regs(state, mode); + + ret = mxl5007t_write_regs(state, init_regs); + if (mxl_fail(ret)) + goto fail; + mdelay(1); + + ret = mxl5007t_write_reg(state, 0x2c, 0x35); + mxl_fail(ret); +fail: + return ret; +} + +static int mxl5007t_tuner_rf_tune(struct mxl5007t_state *state, u32 rf_freq_hz, + enum mxl5007t_bw_mhz bw) +{ + struct reg_pair_t *rf_tune_regs; + int ret; + + /* calculate channel change reg array */ + rf_tune_regs = mxl5007t_calc_rf_tune_regs(state, rf_freq_hz, bw); + + ret = mxl5007t_write_regs(state, rf_tune_regs); + if (mxl_fail(ret)) + goto fail; + msleep(3); +fail: + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_synth_lock_status(struct mxl5007t_state *state, + int *rf_locked, int *ref_locked) +{ + u8 d; + int ret; + + *rf_locked = 0; + *ref_locked = 0; + + ret = mxl5007t_read_reg(state, 0xcf, &d); + if (mxl_fail(ret)) + goto fail; + + if ((d & 0x0c) == 0x0c) + *rf_locked = 1; + + if ((d & 0x03) == 0x03) + *ref_locked = 1; +fail: + return ret; +} + +static int mxl5007t_check_rf_input_power(struct mxl5007t_state *state, + s32 *rf_input_level) +{ + u8 d1, d2; + int ret; + + ret = mxl5007t_read_reg(state, 0xb7, &d1); + if (mxl_fail(ret)) + goto fail; + + ret = mxl5007t_read_reg(state, 0xbf, &d2); + if (mxl_fail(ret)) + goto fail; + + d2 = d2 >> 4; + if (d2 > 7) + d2 += 0xf0; + + *rf_input_level = (s32)(d1 + d2 - 113); +fail: + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct mxl5007t_state *state = fe->tuner_priv; + int rf_locked, ref_locked; + s32 rf_input_level; + int ret; + + mutex_lock(&state->lock); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = mxl5007t_synth_lock_status(state, &rf_locked, &ref_locked); + if (mxl_fail(ret)) + goto fail; + mxl_debug("%s%s", rf_locked ? "rf locked " : "", + ref_locked ? "ref locked" : ""); + + ret = mxl5007t_check_rf_input_power(state, &rf_input_level); + if (mxl_fail(ret)) + goto fail; + mxl_debug("rf input power: %d", rf_input_level); +fail: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + mutex_unlock(&state->lock); + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct mxl5007t_state *state = fe->tuner_priv; + enum mxl5007t_bw_mhz bw; + enum mxl5007t_mode mode; + int ret; + u32 freq = params->frequency; + + if (fe->ops.info.type == FE_ATSC) { + switch (params->u.vsb.modulation) { + case VSB_8: + case VSB_16: + mode = MxL_MODE_OTA_DVBT_ATSC; + break; + case QAM_64: + case QAM_256: + mode = MxL_MODE_CABLE_DIGITAL; + break; + default: + mxl_err("modulation not set!"); + return -EINVAL; + } + bw = MxL_BW_6MHz; + } else if (fe->ops.info.type == FE_OFDM) { + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + bw = MxL_BW_6MHz; + break; + case BANDWIDTH_7_MHZ: + bw = MxL_BW_7MHz; + break; + case BANDWIDTH_8_MHZ: + bw = MxL_BW_8MHz; + break; + default: + mxl_err("bandwidth not set!"); + return -EINVAL; + } + mode = MxL_MODE_OTA_DVBT_ATSC; + } else { + mxl_err("modulation type not supported!"); + return -EINVAL; + } + + mutex_lock(&state->lock); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = mxl5007t_tuner_init(state, mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl5007t_tuner_rf_tune(state, freq, bw); + if (mxl_fail(ret)) + goto fail; + + state->frequency = freq; + state->bandwidth = (fe->ops.info.type == FE_OFDM) ? + params->u.ofdm.bandwidth : 0; +fail: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + mutex_unlock(&state->lock); + return ret; +} + +static int mxl5007t_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct mxl5007t_state *state = fe->tuner_priv; + enum mxl5007t_bw_mhz bw = 0; /* FIXME */ + enum mxl5007t_mode cbl_mode; + enum mxl5007t_mode ota_mode; + char *mode_name; + int ret; + u32 freq = params->frequency * 62500; + +#define cable 1 + if (params->std & V4L2_STD_MN) { + cbl_mode = MxL_MODE_CABLE_NTSC_PAL_GH; + ota_mode = MxL_MODE_OTA_NTSC_PAL_GH; + mode_name = "MN"; + } else if (params->std & V4L2_STD_B) { + cbl_mode = MxL_MODE_CABLE_PAL_IB; + ota_mode = MxL_MODE_OTA_PAL_IB; + mode_name = "B"; + } else if (params->std & V4L2_STD_GH) { + cbl_mode = MxL_MODE_CABLE_NTSC_PAL_GH; + ota_mode = MxL_MODE_OTA_NTSC_PAL_GH; + mode_name = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + cbl_mode = MxL_MODE_CABLE_PAL_IB; + ota_mode = MxL_MODE_OTA_PAL_IB; + mode_name = "I"; + } else if (params->std & V4L2_STD_DK) { + cbl_mode = MxL_MODE_CABLE_PAL_D_SECAM_KL; + ota_mode = MxL_MODE_OTA_PAL_D_SECAM_KL; + mode_name = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + cbl_mode = MxL_MODE_CABLE_PAL_D_SECAM_KL; + ota_mode = MxL_MODE_OTA_PAL_D_SECAM_KL; + mode_name = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + cbl_mode = MxL_MODE_CABLE_PAL_D_SECAM_KL; + ota_mode = MxL_MODE_OTA_PAL_D_SECAM_KL; + mode_name = "L'"; + } else { + mode_name = "xx"; + /* FIXME */ + cbl_mode = MxL_MODE_CABLE_NTSC_PAL_GH; + ota_mode = MxL_MODE_OTA_NTSC_PAL_GH; + } + mxl_debug("setting mxl5007 to system %s", mode_name); + + mutex_lock(&state->lock); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = mxl5007t_tuner_init(state, cable ? cbl_mode : ota_mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl5007t_tuner_rf_tune(state, freq, bw); + if (mxl_fail(ret)) + goto fail; + + state->frequency = freq; + state->bandwidth = 0; +fail: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + mutex_unlock(&state->lock); + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_init(struct dvb_frontend *fe) +{ + struct mxl5007t_state *state = fe->tuner_priv; + //int ret; + + mutex_lock(&state->lock); + /* do init */ +//fail: + mutex_unlock(&state->lock); + + return 0;//ret; +} + +static int mxl5007t_sleep(struct dvb_frontend *fe) +{ + struct mxl5007t_state *state = fe->tuner_priv; + //int ret; + + mutex_lock(&state->lock); + /* do standby */ +//fail: + mutex_unlock(&state->lock); + + return 0;//ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mxl5007t_state *state = fe->tuner_priv; + *frequency = state->frequency; + return 0; +} + +static int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mxl5007t_state *state = fe->tuner_priv; + *bandwidth = state->bandwidth; + return 0; +} + +static int mxl5007t_release(struct dvb_frontend *fe) +{ + struct mxl5007t_state *state = fe->tuner_priv; + + mutex_lock(&mxl5007t_list_mutex); + + if (state) + hybrid_tuner_release_state(state); + + mutex_unlock(&mxl5007t_list_mutex); + + fe->tuner_priv = NULL; + + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static struct dvb_tuner_ops mxl5007t_tuner_ops = { + .info = { + .name = "MaxLinear MxL5007T", + }, + .init = mxl5007t_init, + .sleep = mxl5007t_sleep, + .set_params = mxl5007t_set_params, + .set_analog_params = mxl5007t_set_analog_params, + .get_status = mxl5007t_get_status, + .get_frequency = mxl5007t_get_frequency, + .get_bandwidth = mxl5007t_get_bandwidth, + .release = mxl5007t_release, +}; + +static int mxl5007t_get_chip_id(struct mxl5007t_state *state) +{ + char *name; + int ret; + u8 id; + + ret = mxl5007t_read_reg(state, 0xd3, &id); + if (mxl_fail(ret)) + goto fail; + + switch (id) { + case MxL_5007_V1_F1: + name = "MxL5007.v1.f1"; + break; + case MxL_5007_V1_F2: + name = "MxL5007.v1.f2"; + break; + case MxL_5007_V2_100_F1: + name = "MxL5007.v2.100.f1"; + break; + case MxL_5007_V2_100_F2: + name = "MxL5007.v2.100.f2"; + break; + case MxL_5007_V2_200_F1: + name = "MxL5007.v2.200.f1"; + break; + case MxL_5007_V2_200_F2: + name = "MxL5007.v2.200.f2"; + break; + default: + name = "MxL5007T"; + id = MxL_UNKNOWN_ID; + } + state->chip_id = id; + mxl_info("%s detected @ %d-%04x", name, + i2c_adapter_id(state->i2c_props.adap), + state->i2c_props.addr); + return 0; +fail: + mxl_warn("unable to identify device @ %d-%04x", + i2c_adapter_id(state->i2c_props.adap), + state->i2c_props.addr); + + state->chip_id = MxL_UNKNOWN_ID; + return ret; +} + +struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 addr, + struct mxl5007t_config *cfg) +{ + struct mxl5007t_state *state = NULL; + int instance, ret; + + mutex_lock(&mxl5007t_list_mutex); + instance = hybrid_tuner_request_state(struct mxl5007t_state, state, + hybrid_tuner_instance_list, + i2c, addr, "mxl5007"); + switch (instance) { + case 0: + goto fail; + break; + case 1: + /* new tuner instance */ + state->config = cfg; + + mutex_init(&state->lock); + + mutex_lock(&state->lock); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = mxl5007t_get_chip_id(state); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + mutex_unlock(&state->lock); + + /* check return value of mxl5007t_get_chip_id */ + if (mxl_fail(ret)) + goto fail; + break; + default: + /* existing tuner instance */ + break; + } + fe->tuner_priv = state; + mutex_unlock(&mxl5007t_list_mutex); + + memcpy(&fe->ops.tuner_ops, &mxl5007t_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + return fe; +fail: + mutex_unlock(&mxl5007t_list_mutex); + + mxl5007t_release(fe); + return NULL; +} +EXPORT_SYMBOL_GPL(mxl5007t_attach); +MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver"); +MODULE_AUTHOR("Michael Krufky "); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/common/tuners/mxl5007t.h b/drivers/media/common/tuners/mxl5007t.h new file mode 100644 index 00000000000..a1ee3628b7f --- /dev/null +++ b/drivers/media/common/tuners/mxl5007t.h @@ -0,0 +1,105 @@ +/* + * mxl5007t.h - driver for the MaxLinear MxL5007T silicon tuner + * + * Copyright (C) 2008 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __MXL5007T_H__ +#define __MXL5007T_H__ + +#include "dvb_frontend.h" + +/* ------------------------------------------------------------------------- */ + +enum mxl5007t_if_freq { + MxL_IF_4_MHZ, /* 4000000 */ + MxL_IF_4_5_MHZ, /* 4500000 */ + MxL_IF_4_57_MHZ, /* 4570000 */ + MxL_IF_5_MHZ, /* 5000000 */ + MxL_IF_5_38_MHZ, /* 5380000 */ + MxL_IF_6_MHZ, /* 6000000 */ + MxL_IF_6_28_MHZ, /* 6280000 */ + MxL_IF_9_1915_MHZ, /* 9191500 */ + MxL_IF_35_25_MHZ, /* 35250000 */ + MxL_IF_36_15_MHZ, /* 36150000 */ + MxL_IF_44_MHZ, /* 44000000 */ +}; + +enum mxl5007t_xtal_freq { + MxL_XTAL_16_MHZ, /* 16000000 */ + MxL_XTAL_20_MHZ, /* 20000000 */ + MxL_XTAL_20_25_MHZ, /* 20250000 */ + MxL_XTAL_20_48_MHZ, /* 20480000 */ + MxL_XTAL_24_MHZ, /* 24000000 */ + MxL_XTAL_25_MHZ, /* 25000000 */ + MxL_XTAL_25_14_MHZ, /* 25140000 */ + MxL_XTAL_27_MHZ, /* 27000000 */ + MxL_XTAL_28_8_MHZ, /* 28800000 */ + MxL_XTAL_32_MHZ, /* 32000000 */ + MxL_XTAL_40_MHZ, /* 40000000 */ + MxL_XTAL_44_MHZ, /* 44000000 */ + MxL_XTAL_48_MHZ, /* 48000000 */ + MxL_XTAL_49_3811_MHZ, /* 49381100 */ +}; + +enum mxl5007t_clkout_amp { + MxL_CLKOUT_AMP_0_94V = 0, + MxL_CLKOUT_AMP_0_53V = 1, + MxL_CLKOUT_AMP_0_37V = 2, + MxL_CLKOUT_AMP_0_28V = 3, + MxL_CLKOUT_AMP_0_23V = 4, + MxL_CLKOUT_AMP_0_20V = 5, + MxL_CLKOUT_AMP_0_17V = 6, + MxL_CLKOUT_AMP_0_15V = 7, +}; + +struct mxl5007t_config { + s32 if_diff_out_level; + enum mxl5007t_clkout_amp clk_out_amp; + enum mxl5007t_xtal_freq xtal_freq_hz; + enum mxl5007t_if_freq if_freq_hz; + unsigned int invert_if:1; + unsigned int loop_thru_enable:1; + unsigned int clk_out_enable:1; +}; + +#define CONFIG_MEDIA_TUNER_MXL5007T +#if defined(CONFIG_MEDIA_TUNER_MXL5007T) || (defined(CONFIG_MEDIA_TUNER_MXL5007T_MODULE) && defined(MODULE)) +extern struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 addr, + struct mxl5007t_config *cfg); +#else +static inline struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + u8 addr, + struct mxl5007t_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __MXL5007T_H__ */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ + -- cgit v1.2.3 From 452a53a247d9181bb0ec07ce1def51769619e9d2 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 12 Jul 2008 18:22:38 -0300 Subject: V4L/DVB (8529): mxl5007t: enable _init and _sleep power management functionality Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/mxl5007t.c | 42 +++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/common/tuners/mxl5007t.c index 80cfa9ba1dc..f3b193ac661 100644 --- a/drivers/media/common/tuners/mxl5007t.c +++ b/drivers/media/common/tuners/mxl5007t.c @@ -830,27 +830,53 @@ fail: static int mxl5007t_init(struct dvb_frontend *fe) { struct mxl5007t_state *state = fe->tuner_priv; - //int ret; + int ret; + u8 d; mutex_lock(&state->lock); - /* do init */ -//fail: + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = mxl5007t_read_reg(state, 0x05, &d); + if (mxl_fail(ret)) + goto fail; + + ret = mxl5007t_write_reg(state, 0x05, d | 0x01); + mxl_fail(ret); +fail: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + mutex_unlock(&state->lock); - return 0;//ret; + return ret; } static int mxl5007t_sleep(struct dvb_frontend *fe) { struct mxl5007t_state *state = fe->tuner_priv; - //int ret; + int ret; + u8 d; mutex_lock(&state->lock); - /* do standby */ -//fail: + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = mxl5007t_read_reg(state, 0x05, &d); + if (mxl_fail(ret)) + goto fail; + + ret = mxl5007t_write_reg(state, 0x05, d & ~0x01); + mxl_fail(ret); +fail: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + mutex_unlock(&state->lock); - return 0;//ret; + return ret; } /* ------------------------------------------------------------------------- */ -- cgit v1.2.3 From 59d27521c0f50fadf3382e2b325a7e8a04d9a770 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 9 Jul 2008 00:23:08 -0300 Subject: V4L/DVB (8530): au0828: add support for new revision of HVR950Q Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/au0828/Kconfig | 1 + drivers/media/video/au0828/au0828-cards.c | 12 ++++++++++++ drivers/media/video/au0828/au0828-cards.h | 1 + drivers/media/video/au0828/au0828-dvb.c | 15 +++++++++++++++ 4 files changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig index 52b2491581a..ed9a50f189f 100644 --- a/drivers/media/video/au0828/Kconfig +++ b/drivers/media/video/au0828/Kconfig @@ -6,6 +6,7 @@ config VIDEO_AU0828 select VIDEO_TVEEPROM select DVB_AU8522 if !DVB_FE_CUSTOMIZE select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_MXL5007T if !DVB_FE_CUSTOMIZE ---help--- This is a video4linux driver for Auvitek's USB device. diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c index 898e12395e7..443e5900976 100644 --- a/drivers/media/video/au0828/au0828-cards.c +++ b/drivers/media/video/au0828/au0828-cards.c @@ -32,6 +32,9 @@ struct au0828_board au0828_boards[] = { [AU0828_BOARD_HAUPPAUGE_HVR950Q] = { .name = "Hauppauge HVR950Q", }, + [AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = { + .name = "Hauppauge HVR950Q rev xxF8", + }, [AU0828_BOARD_DVICO_FUSIONHDTV7] = { .name = "DViCO FusionHDTV USB", }, @@ -49,6 +52,7 @@ int au0828_tuner_callback(void *priv, int command, int arg) switch (dev->board) { case AU0828_BOARD_HAUPPAUGE_HVR850: case AU0828_BOARD_HAUPPAUGE_HVR950Q: + case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: case AU0828_BOARD_DVICO_FUSIONHDTV7: if (command == 0) { /* Tuner Reset Command from xc5000 */ @@ -110,6 +114,7 @@ void au0828_card_setup(struct au0828_dev *dev) switch (dev->board) { case AU0828_BOARD_HAUPPAUGE_HVR850: case AU0828_BOARD_HAUPPAUGE_HVR950Q: + case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: if (dev->i2c_rc == 0) hauppauge_eeprom(dev, eeprom+0xa0); break; @@ -128,6 +133,7 @@ void au0828_gpio_setup(struct au0828_dev *dev) switch (dev->board) { case AU0828_BOARD_HAUPPAUGE_HVR850: case AU0828_BOARD_HAUPPAUGE_HVR950Q: + case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: /* GPIO's * 4 - CS5340 * 5 - AU8522 Demodulator @@ -193,6 +199,12 @@ struct usb_device_id au0828_usb_id_table [] = { .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, { USB_DEVICE(0x0fd9, 0x0008), .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, + { USB_DEVICE(0x2040, 0x7201), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, + { USB_DEVICE(0x2040, 0x7211), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, + { USB_DEVICE(0x2040, 0x7281), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, { }, }; diff --git a/drivers/media/video/au0828/au0828-cards.h b/drivers/media/video/au0828/au0828-cards.h index e26f54a961d..c37f5fd0fa8 100644 --- a/drivers/media/video/au0828/au0828-cards.h +++ b/drivers/media/video/au0828/au0828-cards.h @@ -23,3 +23,4 @@ #define AU0828_BOARD_HAUPPAUGE_HVR950Q 1 #define AU0828_BOARD_HAUPPAUGE_HVR850 2 #define AU0828_BOARD_DVICO_FUSIONHDTV7 3 +#define AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL 4 diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c index c6d47059038..584a83a94a2 100644 --- a/drivers/media/video/au0828/au0828-dvb.c +++ b/drivers/media/video/au0828/au0828-dvb.c @@ -28,6 +28,7 @@ #include "au0828.h" #include "au8522.h" #include "xc5000.h" +#include "mxl5007t.h" DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); @@ -45,6 +46,11 @@ static struct xc5000_config hauppauge_hvr950q_tunerconfig = { .tuner_callback = au0828_tuner_callback }; +static struct mxl5007t_config mxl5007t_hvr950q_config = { + .xtal_freq_hz = MxL_XTAL_24_MHZ, + .if_freq_hz = MxL_IF_6_MHZ, +}; + /*-------------------------------------------------------------------*/ static void urb_completion(struct urb *purb) { @@ -342,6 +348,15 @@ int au0828_dvb_register(struct au0828_dev *dev) &dev->i2c_adap, &hauppauge_hvr950q_tunerconfig, dev); break; + case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: + dvb->frontend = dvb_attach(au8522_attach, + &hauppauge_hvr950q_config, + &dev->i2c_adap); + if (dvb->frontend != NULL) + dvb_attach(mxl5007t_attach, dvb->frontend, + &dev->i2c_adap, 0x60, + &mxl5007t_hvr950q_config); + break; default: printk(KERN_WARNING "The frontend of your DVB/ATSC card " "isn't supported yet\n"); -- cgit v1.2.3 From c39c1fd29373d204b11b71946d0f4c97e4974dd9 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 26 Jul 2008 12:06:57 -0300 Subject: V4L/DVB (8531): mxl5007t: move i2c gate handling outside of mutex protected code blocks There is no reason to protect the i2c gate handling within the mxl5007t state mutex. Thanks to Steven Toth for pointing this out. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/mxl5007t.c | 45 ++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/common/tuners/mxl5007t.c index f3b193ac661..4a1ea542585 100644 --- a/drivers/media/common/tuners/mxl5007t.c +++ b/drivers/media/common/tuners/mxl5007t.c @@ -660,11 +660,11 @@ static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status) s32 rf_input_level; int ret; - mutex_lock(&state->lock); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + mutex_lock(&state->lock); + ret = mxl5007t_synth_lock_status(state, &rf_locked, &ref_locked); if (mxl_fail(ret)) goto fail; @@ -676,10 +676,11 @@ static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status) goto fail; mxl_debug("rf input power: %d", rf_input_level); fail: + mutex_unlock(&state->lock); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - mutex_unlock(&state->lock); return ret; } @@ -730,11 +731,11 @@ static int mxl5007t_set_params(struct dvb_frontend *fe, return -EINVAL; } - mutex_lock(&state->lock); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + mutex_lock(&state->lock); + ret = mxl5007t_tuner_init(state, mode); if (mxl_fail(ret)) goto fail; @@ -747,10 +748,11 @@ static int mxl5007t_set_params(struct dvb_frontend *fe, state->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; fail: + mutex_unlock(&state->lock); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - mutex_unlock(&state->lock); return ret; } @@ -802,11 +804,11 @@ static int mxl5007t_set_analog_params(struct dvb_frontend *fe, } mxl_debug("setting mxl5007 to system %s", mode_name); - mutex_lock(&state->lock); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + mutex_lock(&state->lock); + ret = mxl5007t_tuner_init(state, cable ? cbl_mode : ota_mode); if (mxl_fail(ret)) goto fail; @@ -818,10 +820,11 @@ static int mxl5007t_set_analog_params(struct dvb_frontend *fe, state->frequency = freq; state->bandwidth = 0; fail: + mutex_unlock(&state->lock); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - mutex_unlock(&state->lock); return ret; } @@ -833,11 +836,11 @@ static int mxl5007t_init(struct dvb_frontend *fe) int ret; u8 d; - mutex_lock(&state->lock); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + mutex_lock(&state->lock); + ret = mxl5007t_read_reg(state, 0x05, &d); if (mxl_fail(ret)) goto fail; @@ -845,11 +848,11 @@ static int mxl5007t_init(struct dvb_frontend *fe) ret = mxl5007t_write_reg(state, 0x05, d | 0x01); mxl_fail(ret); fail: + mutex_unlock(&state->lock); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - mutex_unlock(&state->lock); - return ret; } @@ -859,11 +862,11 @@ static int mxl5007t_sleep(struct dvb_frontend *fe) int ret; u8 d; - mutex_lock(&state->lock); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + mutex_lock(&state->lock); + ret = mxl5007t_read_reg(state, 0x05, &d); if (mxl_fail(ret)) goto fail; @@ -871,11 +874,11 @@ static int mxl5007t_sleep(struct dvb_frontend *fe) ret = mxl5007t_write_reg(state, 0x05, d & ~0x01); mxl_fail(ret); fail: + mutex_unlock(&state->lock); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - mutex_unlock(&state->lock); - return ret; } @@ -995,18 +998,18 @@ struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, mutex_init(&state->lock); - mutex_lock(&state->lock); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + mutex_lock(&state->lock); + ret = mxl5007t_get_chip_id(state); + mutex_unlock(&state->lock); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - mutex_unlock(&state->lock); - /* check return value of mxl5007t_get_chip_id */ if (mxl_fail(ret)) goto fail; -- cgit v1.2.3 From 74b9ef21162fd81d9de87319c4373f523e2869cd Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 26 Jul 2008 15:43:17 -0300 Subject: V4L/DVB (8532): mxl5007t: remove excessive locks The use of mutex locking is overly paranoid in this driver. The only locks we need are around the manipulation of the register arrays. The other locks are not needed - remove them. Thanks to Steven Toth for pointing this out. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/mxl5007t.c | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/common/tuners/mxl5007t.c index 4a1ea542585..cb25e43502f 100644 --- a/drivers/media/common/tuners/mxl5007t.c +++ b/drivers/media/common/tuners/mxl5007t.c @@ -663,8 +663,6 @@ static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status) if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - mutex_lock(&state->lock); - ret = mxl5007t_synth_lock_status(state, &rf_locked, &ref_locked); if (mxl_fail(ret)) goto fail; @@ -676,8 +674,6 @@ static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status) goto fail; mxl_debug("rf input power: %d", rf_input_level); fail: - mutex_unlock(&state->lock); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); @@ -839,8 +835,6 @@ static int mxl5007t_init(struct dvb_frontend *fe) if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - mutex_lock(&state->lock); - ret = mxl5007t_read_reg(state, 0x05, &d); if (mxl_fail(ret)) goto fail; @@ -848,8 +842,6 @@ static int mxl5007t_init(struct dvb_frontend *fe) ret = mxl5007t_write_reg(state, 0x05, d | 0x01); mxl_fail(ret); fail: - mutex_unlock(&state->lock); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); @@ -865,8 +857,6 @@ static int mxl5007t_sleep(struct dvb_frontend *fe) if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - mutex_lock(&state->lock); - ret = mxl5007t_read_reg(state, 0x05, &d); if (mxl_fail(ret)) goto fail; @@ -874,8 +864,6 @@ static int mxl5007t_sleep(struct dvb_frontend *fe) ret = mxl5007t_write_reg(state, 0x05, d & ~0x01); mxl_fail(ret); fail: - mutex_unlock(&state->lock); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); @@ -1001,12 +989,8 @@ struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - mutex_lock(&state->lock); - ret = mxl5007t_get_chip_id(state); - mutex_unlock(&state->lock); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); -- cgit v1.2.3 From 445c2714cf72817ab1ad3ca894c6d9b2047b3a3e Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 27 Jul 2008 10:04:55 -0300 Subject: V4L/DVB (8534): remove select's of FW_LOADER After commit d9b19199e4894089456aaad295023263b5225c1a (always enable FW_LOADER unless EMBEDDED=y) we can remove the FW_LOADER select's and corresponding dependencies on HOTPLUG. Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/Kconfig | 9 ++------- drivers/media/dvb/bt8xx/Kconfig | 2 -- drivers/media/dvb/dvb-usb/Kconfig | 2 -- drivers/media/dvb/frontends/Kconfig | 24 ++++++++---------------- drivers/media/dvb/ttpci/Kconfig | 4 ---- drivers/media/dvb/ttusb-dec/Kconfig | 2 -- drivers/media/video/bt8xx/Kconfig | 2 -- drivers/media/video/cx18/Kconfig | 2 -- drivers/media/video/cx23885/Kconfig | 2 -- drivers/media/video/cx25840/Kconfig | 2 -- drivers/media/video/cx88/Kconfig | 3 +-- drivers/media/video/ivtv/Kconfig | 2 -- drivers/media/video/pvrusb2/Kconfig | 2 -- drivers/media/video/saa7134/Kconfig | 2 -- 14 files changed, 11 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig index 8d93ba85736..6f92beaa5ac 100644 --- a/drivers/media/common/tuners/Kconfig +++ b/drivers/media/common/tuners/Kconfig @@ -21,9 +21,8 @@ config MEDIA_TUNER tristate default VIDEO_MEDIA && I2C depends on VIDEO_MEDIA && I2C - select FW_LOADER if !MEDIA_TUNER_CUSTOMIZE && HOTPLUG - select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE && HOTPLUG - select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE && HOTPLUG + select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMIZE select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMIZE select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMIZE @@ -138,8 +137,6 @@ config MEDIA_TUNER_QT1010 config MEDIA_TUNER_XC2028 tristate "XCeive xc2028/xc3028 tuners" depends on VIDEO_MEDIA && I2C - depends on HOTPLUG - select FW_LOADER default m if MEDIA_TUNER_CUSTOMIZE help Say Y here to include support for the xc2028/xc3028 tuners. @@ -147,8 +144,6 @@ config MEDIA_TUNER_XC2028 config MEDIA_TUNER_XC5000 tristate "Xceive XC5000 silicon tuner" depends on VIDEO_MEDIA && I2C - depends on HOTPLUG - select FW_LOADER default m if DVB_FE_CUSTOMISE help A driver for the silicon tuner XC5000 from Xceive. diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig index 7588db1319d..7e9c090fc04 100644 --- a/drivers/media/dvb/bt8xx/Kconfig +++ b/drivers/media/dvb/bt8xx/Kconfig @@ -1,7 +1,6 @@ config DVB_BT8XX tristate "BT8xx based PCI cards" depends on DVB_CORE && PCI && I2C && VIDEO_BT848 - depends on HOTPLUG # due to FW_LOADER select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_SP887X if !DVB_FE_CUSTOMISE select DVB_NXT6000 if !DVB_FE_CUSTOMISE @@ -10,7 +9,6 @@ config DVB_BT8XX select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE - select FW_LOADER help Support for PCI cards based on the Bt8xx PCI bridge. Examples are the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards, diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 3c663c65ef6..e84152b7576 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -1,8 +1,6 @@ config DVB_USB tristate "Support for various USB DVB devices" depends on DVB_CORE && USB && I2C && INPUT - depends on HOTPLUG # due to FW_LOADER - select FW_LOADER help By enabling this you will be able to choose the various supported USB1.1 and USB2.0 DVB devices. diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index fa7f0c56377..574dffe91b6 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -97,9 +97,8 @@ comment "DVB-T (terrestrial) frontends" config DVB_SP8870 tristate "Spase sp8870 based" - depends on DVB_CORE && I2C && HOTPLUG + depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE - select FW_LOADER help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -110,9 +109,8 @@ config DVB_SP8870 config DVB_SP887X tristate "Spase sp887x based" - depends on DVB_CORE && I2C && HOTPLUG + depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE - select FW_LOADER help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -158,9 +156,8 @@ config DVB_L64781 config DVB_TDA1004X tristate "Philips TDA10045H/TDA10046H based" - depends on DVB_CORE && I2C && HOTPLUG + depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE - select FW_LOADER help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -225,9 +222,8 @@ config DVB_DIB7000P config DVB_TDA10048 tristate "Philips TDA10048HN based" - depends on DVB_CORE && I2C && HOTPLUG + depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE - select FW_LOADER help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -267,9 +263,8 @@ comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends" config DVB_NXT200X tristate "NxtWave Communications NXT2002/NXT2004 based" - depends on DVB_CORE && I2C && HOTPLUG + depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE - select FW_LOADER help An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. @@ -282,9 +277,8 @@ config DVB_NXT200X config DVB_OR51211 tristate "Oren OR51211 based" - depends on DVB_CORE && I2C && HOTPLUG + depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE - select FW_LOADER help An ATSC 8VSB tuner module. Say Y when you want to support this frontend. @@ -295,9 +289,8 @@ config DVB_OR51211 config DVB_OR51132 tristate "Oren OR51132 based" - depends on DVB_CORE && I2C && HOTPLUG + depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE - select FW_LOADER help An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. @@ -311,9 +304,8 @@ config DVB_OR51132 config DVB_BCM3510 tristate "Broadcom BCM3510" - depends on DVB_CORE && I2C && HOTPLUG + depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE - select FW_LOADER help An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index 87c973ac668..41b5a988b61 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -5,8 +5,6 @@ config TTPCI_EEPROM config DVB_AV7110 tristate "AV7110 cards" depends on DVB_CORE && PCI && I2C - depends on HOTPLUG - select FW_LOADER if !DVB_AV7110_FIRMWARE select TTPCI_EEPROM select VIDEO_SAA7146_VV depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV @@ -127,14 +125,12 @@ config DVB_BUDGET_AV depends on DVB_BUDGET_CORE && I2C select VIDEO_SAA7146_VV depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV - depends on HOTPLUG # dependency of FW_LOADER select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE select DVB_TDA10021 if !DVB_FE_CUSTOMISE select DVB_TDA10023 if !DVB_FE_CUSTOMISE select DVB_TUA6100 if !DVB_FE_CUSTOMISE - select FW_LOADER help Support for simple SAA7146 based DVB cards (so called Budget- or Nova-PCI cards) without onboard diff --git a/drivers/media/dvb/ttusb-dec/Kconfig b/drivers/media/dvb/ttusb-dec/Kconfig index a23cc0aa17d..d5f48a3102b 100644 --- a/drivers/media/dvb/ttusb-dec/Kconfig +++ b/drivers/media/dvb/ttusb-dec/Kconfig @@ -1,8 +1,6 @@ config DVB_TTUSB_DEC tristate "Technotrend/Hauppauge USB DEC devices" depends on DVB_CORE && USB && INPUT - depends on HOTPLUG # due to FW_LOADER - select FW_LOADER select CRC32 help Support for external USB adapters designed by Technotrend and diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig index 24a34fc1f2b..ce71e8e7b83 100644 --- a/drivers/media/video/bt8xx/Kconfig +++ b/drivers/media/video/bt8xx/Kconfig @@ -1,9 +1,7 @@ config VIDEO_BT848 tristate "BT848 Video For Linux" depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 && INPUT - depends on HOTPLUG # due to FW_LOADER select I2C_ALGOBIT - select FW_LOADER select VIDEO_BTCX select VIDEOBUF_DMA_SG select VIDEO_IR diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig index 9aefdc5ea79..ef48565de7f 100644 --- a/drivers/media/video/cx18/Kconfig +++ b/drivers/media/video/cx18/Kconfig @@ -2,9 +2,7 @@ config VIDEO_CX18 tristate "Conexant cx23418 MPEG encoder support" depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL depends on INPUT # due to VIDEO_IR - depends on HOTPLUG # due to FW_LOADER select I2C_ALGOBIT - select FW_LOADER select VIDEO_IR select VIDEO_TUNER select VIDEO_TVEEPROM diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 5cfb46bbdaa..e60bd31b51a 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -1,9 +1,7 @@ config VIDEO_CX23885 tristate "Conexant cx23885 (2388x successor) support" depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT - depends on HOTPLUG # due to FW_LOADER select I2C_ALGOBIT - select FW_LOADER select VIDEO_BTCX select VIDEO_TUNER select VIDEO_TVEEPROM diff --git a/drivers/media/video/cx25840/Kconfig b/drivers/media/video/cx25840/Kconfig index 448f4cd0ce3..de515dadadc 100644 --- a/drivers/media/video/cx25840/Kconfig +++ b/drivers/media/video/cx25840/Kconfig @@ -1,8 +1,6 @@ config VIDEO_CX25840 tristate "Conexant CX2584x audio/video decoders" depends on VIDEO_V4L2 && I2C && EXPERIMENTAL - depends on HOTPLUG # due to FW_LOADER - select FW_LOADER ---help--- Support for the Conexant CX2584x audio/video decoders. diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index 10e20d8196d..9dd7bdf659b 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -33,9 +33,8 @@ config VIDEO_CX88_ALSA config VIDEO_CX88_BLACKBIRD tristate "Blackbird MPEG encoder support (cx2388x + cx23416)" - depends on VIDEO_CX88 && HOTPLUG + depends on VIDEO_CX88 select VIDEO_CX2341X - select FW_LOADER ---help--- This adds support for MPEG encoder cards based on the Blackbird reference design, using the Conexant 2388x diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index 5d7ee8fcdd5..0069898bdda 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -2,9 +2,7 @@ config VIDEO_IVTV tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support" depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL depends on INPUT # due to VIDEO_IR - depends on HOTPLUG # due to FW_LOADER select I2C_ALGOBIT - select FW_LOADER select VIDEO_IR select VIDEO_TUNER select VIDEO_TVEEPROM diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig index 4482b2c72ce..19eb274c9cd 100644 --- a/drivers/media/video/pvrusb2/Kconfig +++ b/drivers/media/video/pvrusb2/Kconfig @@ -2,8 +2,6 @@ config VIDEO_PVRUSB2 tristate "Hauppauge WinTV-PVR USB2 support" depends on VIDEO_V4L2 && I2C depends on VIDEO_MEDIA # Avoids pvrusb = Y / DVB = M - depends on HOTPLUG # due to FW_LOADER - select FW_LOADER select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 83f076abce3..7021bbf5897 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -27,9 +27,7 @@ config VIDEO_SAA7134_ALSA config VIDEO_SAA7134_DVB tristate "DVB/ATSC Support for saa7134 based TV cards" depends on VIDEO_SAA7134 && DVB_CORE - depends on HOTPLUG # due to FW_LOADER select VIDEOBUF_DVB - select FW_LOADER select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE -- cgit v1.2.3 From 59d07f1b705c466ea4eaca9c43d46be6d6a065a4 Mon Sep 17 00:00:00 2001 From: Aron Szabo Date: Sun, 27 Jul 2008 13:47:52 -0300 Subject: V4L/DVB (8538): em28xx-cards: Add GrabBeeX+ USB2800 model Added GrabBeeX+ USB2800 model (analog only) [mchehab@infradead.org: Need to fix some merge conflicts] Signed-off-by: Aron Szabo Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 19 +++++++++++++++++++ drivers/media/video/em28xx/em28xx.h | 1 + 2 files changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 81f9ff55588..9b29c8f4c18 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -375,6 +375,21 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, + [EM2800_BOARD_GRABBEEX_USB2800] = { + .name = "eMPIA Technology, Inc. GrabBeeX+ Video Encoder", + .is_em2800 = 1, + .vchannels = 2, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, [EM2800_BOARD_LEADTEK_WINFAST_USBII] = { .name = "Leadtek Winfast USB II", .is_em2800 = 1, @@ -541,6 +556,8 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, { USB_DEVICE(0x0438, 0xb002), .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, + { USB_DEVICE(0xeb1a, 0x2801), + .driver_info = EM2800_BOARD_GRABBEEX_USB2800 }, { }, }; MODULE_DEVICE_TABLE(usb, em28xx_id_table); @@ -863,6 +880,8 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir) break; case (EM2800_BOARD_KWORLD_USB2800): break; + case (EM2800_BOARD_GRABBEEX_USB2800): + break; } } diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 9da877375cf..84bc0b902ac 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -59,6 +59,7 @@ #define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18 #define EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA 19 #define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 20 +#define EM2800_BOARD_GRABBEEX_USB2800 21 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 -- cgit v1.2.3 From 95b86a9a9020da22e7c25abc77aae4dc8f02ab55 Mon Sep 17 00:00:00 2001 From: Douglas Schilling Landgraf Date: Sun, 27 Jul 2008 14:03:32 -0300 Subject: V4L/DVB (8539): em28xx-cards: New supported IDs for analog models - New supported IDs for analog models (Based on Markus Rechberger version of em28xx driver) - Validation field for new em28xx boards. Signed-off-by: Douglas Schilling Landgraf [mchehab@infradead.org: Need to fix some merge conflicts] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 1220 +++++++++++++++++++++++++---- drivers/media/video/em28xx/em28xx.h | 45 +- 2 files changed, 1091 insertions(+), 174 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 9b29c8f4c18..e3e965defd5 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -52,6 +52,15 @@ struct em28xx_hash_table { }; struct em28xx_board em28xx_boards[] = { + [EM2750_BOARD_UNKNOWN] = { + .name = "Unknown EM2750/EM2751 webcam grabber", + .vchannels = 1, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = 0, + .amux = 0, + } }, + }, [EM2800_BOARD_UNKNOWN] = { .name = "Unknown EM2800 video grabber", .is_em2800 = 1, @@ -73,6 +82,39 @@ struct em28xx_board em28xx_boards[] = { .is_em2800 = 0, .tuner_type = TUNER_ABSENT, }, + [EM2750_BOARD_DLCW_130] = { + /* Beijing Huaqi Information Digital Technology Co., Ltd */ + .name = "Huaqi DLCW-130", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 1, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = 0, + .amux = 0, + } }, + }, + [EM2800_BOARD_KWORLD_USB2800] = { + .name = "Kworld USB2800", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .is_em2800 = 1, + .vchannels = 3, + .tuner_type = TUNER_PHILIPS_FCV1236D, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, [EM2820_BOARD_KWORLD_PVRTV2800RF] = { .name = "Kworld PVR TV 2800 RF", .is_em2800 = 0, @@ -151,13 +193,251 @@ struct em28xx_board em28xx_boards[] = { MSP_DSP_IN_SCART, MSP_DSP_IN_SCART), } }, }, - [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { - .name = "Hauppauge WinTV HVR 900", + [EM2820_BOARD_DLINK_USB_TV] = { + .name = "D-Link DUB-T210 TV Tuner", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .is_em2800 = 0, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 1, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2820_BOARD_HERCULES_SMART_TV_USB2] = { + .name = "Hercules Smart TV USB 2.0", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 1, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2820_BOARD_PINNACLE_USB_2_FM1216ME] = { + .name = "Pinnacle PCTV USB 2 (Philips FM1216ME)", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .is_em2800 = 0, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2820_BOARD_GADMEI_UTV310] = { + .name = "Gadmei UTV310", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_TNF_5335MF, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE] = { + .name = "Leadtek Winfast USB II Deluxe", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7114, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = 2, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = 0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = 9, + .amux = 1, + } }, + }, + [EM2820_BOARD_PINNACLE_DVC_100] = { + .name = "Pinnacle Dazzle DVC 100", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2820_BOARD_VIDEOLOGY_20K14XUSB] = { + .name = "Videology 20K14XUSB USB2.0", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 1, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = 0, + .amux = 0, + } }, + }, + [EM2821_BOARD_PROLINK_PLAYTV_USB2] = { + .name = "SIIG AVTuner-PVR/Prolink PlayTV USB 2.0", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .is_em2800 = 0, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, /* unknown? */ + .tda9887_conf = TDA9887_PRESENT, /* unknown? */ + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 1, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2821_BOARD_SUPERCOMP_USB_2] = { + .name = "Supercomp USB 2.0 TV", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .is_em2800 = 0, + .tuner_type = TUNER_PHILIPS_FM1236_MK3, + .tda9887_conf = TDA9887_PRESENT | + TDA9887_PORT1_ACTIVE | + TDA9887_PORT2_ACTIVE, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 1, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2821_BOARD_USBGEAR_VD204] = { + .name = "Usbgear VD204v9", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 2, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2860_BOARD_NETGMBH_CAM] = { + /* Beijing Huaqi Information Digital Technology Co., Ltd */ + .name = "NetGMBH Cam", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 1, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = 0, + .amux = 0, + } }, + }, + [EM2860_BOARD_TYPHOON_DVD_MAKER] = { + .name = "Typhoon DVD Maker", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 2, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2860_BOARD_GADMEI_UTV330] = { + .name = "Gadmei UTV330", + .valid = EM28XX_BOARD_NOT_VALIDATED, .vchannels = 3, + .tuner_type = TUNER_TNF_5335MF, .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2860_BOARD_TERRATEC_HYBRID_XS] = { + .name = "Terratec Cinergy A Hybrid XS", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, .tuner_type = TUNER_XC2028, - .mts_firmware = 1, - .has_dvb = 1, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -173,12 +453,11 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, - [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2] = { - .name = "Hauppauge WinTV HVR 900 (R2)", + [EM2861_BOARD_KWORLD_PVRTV_300U] = { + .name = "KWorld PVRTV 300U", + .valid = EM28XX_BOARD_NOT_VALIDATED, .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, - .mts_firmware = 1, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -194,16 +473,12 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, - [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950] = { - .name = "Hauppauge WinTV HVR 950", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .mts_firmware = 1, - .has_12mhz_i2s = 1, - .has_dvb = 1, - .decoder = EM28XX_TVP5150, - .input = { { + [EM2861_BOARD_YAKUMO_MOVIE_MIXER] = { + .name = "Yakumo MovieMixer", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 1, + .decoder = EM28XX_TVP5150, + .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = 0, @@ -217,19 +492,17 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, - [EM2880_BOARD_PINNACLE_PCTV_HD_PRO] = { - .name = "Pinnacle PCTV HD Pro Stick", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .mts_firmware = 1, - .has_12mhz_i2s = 1, - .has_dvb = 1, - .decoder = EM28XX_TVP5150, + [EM2861_BOARD_PLEXTOR_PX_TV100U] = { + .name = "Plextor ConvertX PX-TV100U", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_TNF_5335MF, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, - .amux = 0, + .amux = 1, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, @@ -240,15 +513,42 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, - [EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = { - .name = "AMD ATI TV Wonder HD 600", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .mts_firmware = 1, - .has_12mhz_i2s = 1, - .has_dvb = 1, - .decoder = EM28XX_TVP5150, + [EM2870_BOARD_TERRATEC_XS] = { + .name = "Terratec Cinergy T XS", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_XC2028, + }, + [EM2870_BOARD_TERRATEC_XS_MT2060] = { + .name = "Terratec Cinergy T XS (MT2060)", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, /* MT2060 */ + }, + [EM2870_BOARD_KWORLD_350U] = { + .name = "Kworld 350 U DVB-T", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_XC2028, + }, + [EM2870_BOARD_KWORLD_355U] = { + .name = "Kworld 355 U DVB-T", + .valid = EM28XX_BOARD_NOT_VALIDATED, + }, + [EM2870_BOARD_PINNACLE_PCTV_DVB] = { + .name = "Pinnacle PCTV DVB-T", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, /* MT2060 */ + }, + [EM2870_BOARD_COMPRO_VIDEOMATE] = { + .name = "Compro, VideoMate U3", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, /* MT2060 */ + }, + [EM2880_BOARD_TERRATEC_HYBRID_XS_FR] = { + .name = "Terratec Hybrid XS Secam", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .has_msp34xx = 1, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, @@ -263,15 +563,382 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, - [EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = { - .name = "AMD ATI TV Wonder HD 600", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .mts_firmware = 1, - .has_12mhz_i2s = 1, - .has_dvb = 1, - .decoder = EM28XX_TVP5150, + [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { + .name = "Hauppauge WinTV HVR 900", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .mts_firmware = 1, + .has_dvb = 1, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2] = { + .name = "Hauppauge WinTV HVR 900 (R2)", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .mts_firmware = 1, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950] = { + .name = "Hauppauge WinTV HVR 950", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .mts_firmware = 1, + .has_12mhz_i2s = 1, + .has_dvb = 1, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2880_BOARD_PINNACLE_PCTV_HD_PRO] = { + .name = "Pinnacle PCTV HD Pro Stick", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .mts_firmware = 1, + .has_12mhz_i2s = 1, + .has_dvb = 1, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = { + .name = "AMD ATI TV Wonder HD 600", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .mts_firmware = 1, + .has_12mhz_i2s = 1, + .has_dvb = 1, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = { + .name = "AMD ATI TV Wonder HD 600", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .mts_firmware = 1, + .has_12mhz_i2s = 1, + .has_dvb = 1, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2880_BOARD_TERRATEC_HYBRID_XS] = { + .name = "Terratec Hybrid XS", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .has_dvb = 1, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + /* maybe there's a reason behind it why Terratec sells the Hybrid XS + as Prodigy XS with a different PID, let's keep it separated for now + maybe we'll need it lateron */ + [EM2880_BOARD_TERRATEC_PRODIGY_XS] = { + .name = "Terratec Prodigy XS", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2820_BOARD_MSI_VOX_USB_2] = { + .name = "MSI VOX USB 2.0", + .vchannels = 3, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT | + TDA9887_PORT1_ACTIVE | + TDA9887_PORT2_ACTIVE, + .max_range_640_480 = 1, + + .decoder = EM28XX_SAA7114, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE4, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2800_BOARD_TERRATEC_CINERGY_200] = { + .name = "Terratec Cinergy 200 USB", + .is_em2800 = 1, + .vchannels = 3, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2800_BOARD_GRABBEEX_USB2800] = { + .name = "eMPIA Technology, Inc. GrabBeeX+ Video Encoder", + .is_em2800 = 1, + .vchannels = 2, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2800_BOARD_LEADTEK_WINFAST_USBII] = { + .name = "Leadtek Winfast USB II", + .is_em2800 = 1, + .vchannels = 3, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2800_BOARD_KWORLD_USB2800] = { + .name = "Kworld USB2800", + .is_em2800 = 1, + .vchannels = 3, + .tuner_type = TUNER_PHILIPS_FCV1236D, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2820_BOARD_PINNACLE_DVC_90] = { + .name = "Pinnacle Dazzle DVC 90/DVC 100", + .vchannels = 3, + .tuner_type = TUNER_ABSENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2800_BOARD_VGEAR_POCKETTV] = { + .name = "V-Gear PocketTV", + .is_em2800 = 1, + .vchannels = 3, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2820_BOARD_PROLINK_PLAYTV_USB2] = { + .name = "Pixelview Prolink PlayTV USB 2.0", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_YMEC_TVF_5533MF, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, + [EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA] = { + .name = "PointNix Intra-Oral Camera", + .has_snapshot_button = 1, + .vchannels = 1, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_ABSENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 0, + } }, + }, + [EM2880_BOARD_MSI_DIGIVOX_AD] = { + .name = "MSI DigiVox A/D", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2880_BOARD_MSI_DIGIVOX_AD_II] = { + .name = "MSI DigiVox A/D II", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, @@ -286,13 +953,12 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, - [EM2880_BOARD_TERRATEC_HYBRID_XS] = { - .name = "Terratec Hybrid XS", + [EM2880_BOARD_KWORLD_DVB_305U] = { + .name = "KWorld DVB-T 305U", + .valid = EM28XX_BOARD_NOT_VALIDATED, .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, .decoder = EM28XX_TVP5150, - .has_dvb = 1, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, @@ -307,13 +973,10 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, - /* maybe there's a reason behind it why Terratec sells the Hybrid XS - as Prodigy XS with a different PID, let's keep it separated for now - maybe we'll need it lateron */ - [EM2880_BOARD_TERRATEC_PRODIGY_XS] = { - .name = "Terratec Prodigy XS", + [EM2880_BOARD_KWORLD_DVB_310U] = { + .name = "KWorld DVB-T 310U", + .valid = EM28XX_BOARD_NOT_VALIDATED, .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, .decoder = EM28XX_TVP5150, .input = { { @@ -330,175 +993,145 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, - [EM2820_BOARD_MSI_VOX_USB_2] = { - .name = "MSI VOX USB 2.0", - .vchannels = 3, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT | - TDA9887_PORT1_ACTIVE | - TDA9887_PORT2_ACTIVE, - .max_range_640_480 = 1, - - .decoder = EM28XX_SAA7114, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE4, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2800_BOARD_TERRATEC_CINERGY_200] = { - .name = "Terratec Cinergy 200 USB", - .is_em2800 = 1, + [EM2881_BOARD_DNT_DA2_HYBRID] = { + .name = "DNT DA2 Hybrid", + .valid = EM28XX_BOARD_NOT_VALIDATED, .vchannels = 3, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, + .vmux = TVP5150_COMPOSITE0, .amux = 0, }, { .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, + .vmux = TVP5150_COMPOSITE1, .amux = 1, }, { .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, + .vmux = TVP5150_SVIDEO, .amux = 1, } }, }, - [EM2800_BOARD_GRABBEEX_USB2800] = { - .name = "eMPIA Technology, Inc. GrabBeeX+ Video Encoder", - .is_em2800 = 1, - .vchannels = 2, - .decoder = EM28XX_SAA7113, + [EM2881_BOARD_PINNACLE_HYBRID_PRO] = { + .name = "Pinnacle Hybrid Pro", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, + .vmux = TVP5150_COMPOSITE1, .amux = 1, }, { .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, + .vmux = TVP5150_SVIDEO, .amux = 1, } }, }, - [EM2800_BOARD_LEADTEK_WINFAST_USBII] = { - .name = "Leadtek Winfast USB II", - .is_em2800 = 1, + [EM2882_BOARD_PINNACLE_HYBRID_PRO] = { + .name = "Pinnacle Hybrid Pro (2)", + .valid = EM28XX_BOARD_NOT_VALIDATED, .vchannels = 3, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, + .vmux = TVP5150_COMPOSITE0, .amux = 0, }, { .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, + .vmux = TVP5150_COMPOSITE1, .amux = 1, }, { .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, + .vmux = TVP5150_SVIDEO, .amux = 1, } }, }, - [EM2800_BOARD_KWORLD_USB2800] = { - .name = "Kworld USB2800", - .is_em2800 = 1, + [EM2882_BOARD_KWORLD_VS_DVBT] = { + .name = "Kworld VS-DVB-T 323UR", + .valid = EM28XX_BOARD_NOT_VALIDATED, .vchannels = 3, - .tuner_type = TUNER_PHILIPS_FCV1236D, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, + .vmux = TVP5150_COMPOSITE0, .amux = 0, }, { .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, + .vmux = TVP5150_COMPOSITE1, .amux = 1, }, { .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, + .vmux = TVP5150_SVIDEO, .amux = 1, } }, }, - [EM2820_BOARD_PINNACLE_DVC_90] = { - .name = "Pinnacle Dazzle DVC 90/DVC 100", + [EM2882_BOARD_TERRATEC_HYBRID_XS] = { + .name = "Terratec Hybrid XS (em2882)", + .valid = EM28XX_BOARD_NOT_VALIDATED, .vchannels = 3, - .tuner_type = TUNER_ABSENT, - .decoder = EM28XX_SAA7113, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, + .vmux = TVP5150_COMPOSITE1, .amux = 1, }, { .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, + .vmux = TVP5150_SVIDEO, .amux = 1, } }, }, - [EM2800_BOARD_VGEAR_POCKETTV] = { - .name = "V-Gear PocketTV", - .is_em2800 = 1, + [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950] = { + .name = "Hauppauge WinTV HVR 950", + .valid = EM28XX_BOARD_NOT_VALIDATED, .vchannels = 3, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, + .vmux = TVP5150_COMPOSITE0, .amux = 0, }, { .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, + .vmux = TVP5150_COMPOSITE1, .amux = 1, }, { .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, + .vmux = TVP5150_SVIDEO, .amux = 1, } }, }, - [EM2820_BOARD_PROLINK_PLAYTV_USB2] = { - .name = "Pixelview Prolink PlayTV USB 2.0", + [EM2883_BOARD_KWORLD_HYBRID_A316] = { + .name = "Kworld PlusTV HD Hybrid 330", + .valid = EM28XX_BOARD_NOT_VALIDATED, .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_YMEC_TVF_5533MF, - .decoder = EM28XX_SAA7113, + .is_em2800 = 0, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_LINE_IN, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, }, { .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, }, { .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA] = { - .name = "PointNix Intra-Oral Camera", - .has_snapshot_button = 1, - .vchannels = 1, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_ABSENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 0, + .vmux = TVP5150_SVIDEO, + .amux = 1, } }, }, }; @@ -507,7 +1140,9 @@ const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); /* table of devices that work with this driver */ struct usb_device_id em28xx_id_table [] = { { USB_DEVICE(0xeb1a, 0x2750), - .driver_info = EM2820_BOARD_UNKNOWN }, + .driver_info = EM2750_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2751), + .driver_info = EM2750_BOARD_UNKNOWN }, { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN }, { USB_DEVICE(0xeb1a, 0x2820), @@ -524,20 +1159,46 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2820_BOARD_UNKNOWN }, { USB_DEVICE(0xeb1a, 0x2883), .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0xe300), + .driver_info = EM2861_BOARD_KWORLD_PVRTV_300U }, + { USB_DEVICE(0xeb1a, 0xe305), + .driver_info = EM2880_BOARD_KWORLD_DVB_305U }, + { USB_DEVICE(0xeb1a, 0xe310), + .driver_info = EM2880_BOARD_MSI_DIGIVOX_AD }, + { USB_DEVICE(0xeb1a, 0xa316), + .driver_info = EM2883_BOARD_KWORLD_HYBRID_A316 }, + { USB_DEVICE(0xeb1a, 0xe320), + .driver_info = EM2880_BOARD_MSI_DIGIVOX_AD_II }, + { USB_DEVICE(0xeb1a, 0xe323), + .driver_info = EM2882_BOARD_KWORLD_VS_DVBT }, + { USB_DEVICE(0xeb1a, 0xe350), + .driver_info = EM2870_BOARD_KWORLD_350U }, + { USB_DEVICE(0xeb1a, 0xe355), + .driver_info = EM2870_BOARD_KWORLD_355U }, + { USB_DEVICE(0xeb1a, 0x2801), + .driver_info = EM2800_BOARD_GRABBEEX_USB2800 }, + { USB_DEVICE(0xeb1a, 0xe357), + .driver_info = EM2870_BOARD_KWORLD_355U }, { USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 }, - { USB_DEVICE(0x2304, 0x0208), - .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, + { USB_DEVICE(0x0ccd, 0x004c), + .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS_FR }, + { USB_DEVICE(0x0ccd, 0x004f), + .driver_info = EM2860_BOARD_TERRATEC_HYBRID_XS }, + { USB_DEVICE(0x0ccd, 0x005e), + .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS }, + { USB_DEVICE(0x0ccd, 0x0042), + .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS }, + { USB_DEVICE(0x0ccd, 0x0043), + .driver_info = EM2870_BOARD_TERRATEC_XS }, + { USB_DEVICE(0x0ccd, 0x0047), + .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, + { USB_DEVICE(0x185b, 0x2870), + .driver_info = EM2870_BOARD_COMPRO_VIDEOMATE }, { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, { USB_DEVICE(0x2040, 0x4201), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, - { USB_DEVICE(0x2304, 0x0207), - .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, - { USB_DEVICE(0x2304, 0x021a), - .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, - { USB_DEVICE(0x2304, 0x0227), - .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO }, { USB_DEVICE(0x2040, 0x6500), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, { USB_DEVICE(0x2040, 0x6502), @@ -550,14 +1211,24 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, { USB_DEVICE(0x2040, 0x651f), /* HCW HVR-850 */ .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, - { USB_DEVICE(0x0ccd, 0x0042), - .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS }, - { USB_DEVICE(0x0ccd, 0x0047), - .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, { USB_DEVICE(0x0438, 0xb002), .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, - { USB_DEVICE(0xeb1a, 0x2801), - .driver_info = EM2800_BOARD_GRABBEEX_USB2800 }, + { USB_DEVICE(0x2001, 0xf112), + .driver_info = EM2820_BOARD_DLINK_USB_TV }, + { USB_DEVICE(0x2304, 0x0207), + .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, + { USB_DEVICE(0x2304, 0x0208), + .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, + { USB_DEVICE(0x2304, 0x021a), + .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, + { USB_DEVICE(0x2304, 0x0226), + .driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO }, + { USB_DEVICE(0x2304, 0x0227), + .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO }, + { USB_DEVICE(0x0413, 0x6023), + .driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII }, + { USB_DEVICE(0x093b, 0xa005), + .driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U }, { }, }; MODULE_DEVICE_TABLE(usb, em28xx_id_table); @@ -566,6 +1237,18 @@ MODULE_DEVICE_TABLE(usb, em28xx_id_table); * Reset sequences for analog/digital modes */ +/* Reset for the most [analog] boards */ +static struct em28xx_reg_seq default_analog[] = { + {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +/* Reset for the most [digital] boards */ +static struct em28xx_reg_seq default_digital[] = { + {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + /* Board Hauppauge WinTV HVR 900 analog */ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = { {EM28XX_R08_GPIO, 0x2d, ~EM_GPIO_4, 10}, @@ -581,14 +1264,42 @@ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = { { -1, -1, -1, -1}, }; -/* Board Hauppauge WinTV HVR 900 tuner_callback */ -static struct em28xx_reg_seq hauppauge_wintv_hvr_900_tuner_callback[] = { +/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ +static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { + {EM28XX_R08_GPIO, 0x69, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ +static struct em28xx_reg_seq em2880_msi_digivox_ad_digital[] = { + {EM28XX_R08_GPIO, 0x6a, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +/* Board - EM2870 Kworld 355u + Analog - No input analog */ +static struct em28xx_reg_seq em2870_kworld_355u_digital[] = { + {EM2880_R04_GPO, 0x01, 0xff, 10}, + { -1, -1, -1, -1}, +}; + +/* Callback for the most boards */ +static struct em28xx_reg_seq default_callback[] = { {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, {EM28XX_R08_GPIO, 0, EM_GPIO_4, 10}, {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, { -1, -1, -1, -1}, }; +/* Callback for EM2882 TERRATEC HYBRID XS */ +static struct em28xx_reg_seq em2882_terratec_hybrid_xs_digital[] = { + {EM28XX_R08_GPIO, 0x2e, 0xff, 6}, + {EM28XX_R08_GPIO, 0x3e, ~EM_GPIO_4, 6}, + {EM2880_R04_GPO, 0x04, 0xff, 10}, + {EM2880_R04_GPO, 0x0c, 0xff, 10}, + { -1, -1, -1, -1}, +}; + /* * EEPROM hash table for devices with generic USB IDs */ @@ -635,6 +1346,7 @@ static void em28xx_set_model(struct em28xx *dev) dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480; dev->has_dvb = em28xx_boards[dev->model].has_dvb; dev->has_snapshot_button = em28xx_boards[dev->model].has_snapshot_button; + dev->valid = em28xx_boards[dev->model].valid; } /* Since em28xx_pre_card_setup() requires a proper dev->model, @@ -670,9 +1382,12 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2880_BOARD_TERRATEC_PRODIGY_XS: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: - case EM2880_BOARD_TERRATEC_HYBRID_XS: + case EM2860_BOARD_TERRATEC_HYBRID_XS: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: + case EM2882_BOARD_PINNACLE_HYBRID_PRO: + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2883_BOARD_KWORLD_HYBRID_A316: case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); @@ -681,9 +1396,158 @@ void em28xx_pre_card_setup(struct em28xx *dev) /* Sets GPO/GPIO sequences for this device */ dev->analog_gpio = hauppauge_wintv_hvr_900_analog; dev->digital_gpio = hauppauge_wintv_hvr_900_digital; - dev->tun_analog_gpio = hauppauge_wintv_hvr_900_tuner_callback; - dev->tun_digital_gpio = hauppauge_wintv_hvr_900_tuner_callback; + dev->tun_analog_gpio = default_callback; + dev->tun_digital_gpio = default_callback; + break; + + case EM2882_BOARD_TERRATEC_HYBRID_XS: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + msleep(50); + + /* should be added ir_codes here */ + + /* Sets GPO/GPIO sequences for this device */ + dev->analog_gpio = hauppauge_wintv_hvr_900_analog; + dev->digital_gpio = hauppauge_wintv_hvr_900_digital; + dev->tun_analog_gpio = default_callback; + dev->tun_digital_gpio = em2882_terratec_hybrid_xs_digital; + break; + + case EM2880_BOARD_TERRATEC_HYBRID_XS_FR: + case EM2880_BOARD_TERRATEC_HYBRID_XS: + case EM2870_BOARD_TERRATEC_XS: + case EM2881_BOARD_PINNACLE_HYBRID_PRO: + case EM2880_BOARD_KWORLD_DVB_310U: + case EM2870_BOARD_KWORLD_350U: + case EM2881_BOARD_DNT_DA2_HYBRID: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + msleep(50); + + /* NOTE: EM2881_DNT_DA2_HYBRID spend 140 msleep for digital + and analog commands. If this commands doesn't work, + add this timer. */ + + /* Sets GPO/GPIO sequences for this device */ + dev->analog_gpio = default_analog; + dev->digital_gpio = default_digital; + dev->tun_analog_gpio = default_callback; + dev->tun_digital_gpio = default_callback; + break; + + case EM2880_BOARD_MSI_DIGIVOX_AD: + case EM2880_BOARD_MSI_DIGIVOX_AD_II: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + msleep(50); + + /* Sets GPO/GPIO sequences for this device */ + dev->analog_gpio = em2880_msi_digivox_ad_analog; + dev->digital_gpio = em2880_msi_digivox_ad_digital; + dev->tun_analog_gpio = default_callback; + dev->tun_digital_gpio = default_callback; + break; + case EM2750_BOARD_UNKNOWN: + case EM2750_BOARD_DLCW_130: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x0a", 1); + break; + + case EM2861_BOARD_PLEXTOR_PX_TV100U: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + /* FIXME guess */ + /* Turn on analog audio output */ + em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1); + break; + + case EM2861_BOARD_KWORLD_PVRTV_300U: + case EM2880_BOARD_KWORLD_DVB_305U: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x4c", 1); + msleep(10); + em28xx_write_regs(dev, 0x08, "\x6d", 1); + msleep(10); + em28xx_write_regs(dev, 0x08, "\x7d", 1); + msleep(10); + break; + + case EM2870_BOARD_KWORLD_355U: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + msleep(50); + + /* Sets GPO/GPIO sequences for this device */ + dev->digital_gpio = em2870_kworld_355u_digital; + break; + + case EM2870_BOARD_COMPRO_VIDEOMATE: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + /* TODO: someone can do some cleanup here... + not everything's needed */ + em28xx_write_regs(dev, 0x04, "\x00", 1); + msleep(10); + em28xx_write_regs(dev, 0x04, "\x01", 1); + msleep(10); + em28xx_write_regs(dev, 0x08, "\xfd", 1); + mdelay(70); + em28xx_write_regs(dev, 0x08, "\xfc", 1); + mdelay(70); + em28xx_write_regs(dev, 0x08, "\xdc", 1); + mdelay(70); + em28xx_write_regs(dev, 0x08, "\xfc", 1); + mdelay(70); + break; + + case EM2870_BOARD_TERRATEC_XS_MT2060: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + /* this device needs some gpio writes to get the DVB-T + demod work */ + em28xx_write_regs(dev, 0x08, "\xfe", 1); + mdelay(70); + em28xx_write_regs(dev, 0x08, "\xde", 1); + mdelay(70); + dev->em28xx_write_regs(dev, 0x08, "\xfe", 1); + mdelay(70); + break; + + case EM2870_BOARD_PINNACLE_PCTV_DVB: + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + /* this device needs some gpio writes to get the + DVB-T demod work */ + em28xx_write_regs(dev, 0x08, "\xfe", 1); + mdelay(70); + em28xx_write_regs(dev, 0x08, "\xde", 1); + mdelay(70); + em28xx_write_regs(dev, 0x08, "\xfe", 1); + mdelay(70); + /* switch em2880 rc protocol */ + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x22", 1); + /* should be added ir_codes here */ + break; + + case EM2820_BOARD_GADMEI_UTV310: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + /* Turn on analog audio output */ + em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1); + break; + + case EM2860_BOARD_GADMEI_UTV330: + /* Turn on IR */ + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x07", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + /* should be added ir_codes here */ + break; + + case EM2820_BOARD_MSI_VOX_USB_2: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + /* enables audio for that device */ + em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1); break; } @@ -927,11 +1791,21 @@ void em28xx_card_setup(struct em28xx *dev) case EM2800_BOARD_UNKNOWN: if (!em28xx_hint_board(dev)) em28xx_set_model(dev); + break; } if (dev->has_snapshot_button) em28xx_register_snapshot_button(dev); + if (dev->valid == EM28XX_BOARD_NOT_VALIDATED) { + em28xx_errdev("\n\n"); + em28xx_errdev("The support for this board weren't " + "valid yet.\n"); + em28xx_errdev("Please send a report of having this working\n"); + em28xx_errdev("not to V4L mailing list (and/or to other " + "addresses)\n\n"); + } + /* Allow override tuner type by a module parameter */ if (tuner >= 0) dev->tuner_type = tuner; diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 84bc0b902ac..1b7364d664b 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -60,11 +60,52 @@ #define EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA 19 #define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 20 #define EM2800_BOARD_GRABBEEX_USB2800 21 +#define EM2750_BOARD_UNKNOWN 22 +#define EM2750_BOARD_DLCW_130 23 +#define EM2820_BOARD_DLINK_USB_TV 24 +#define EM2820_BOARD_GADMEI_UTV310 25 +#define EM2820_BOARD_HERCULES_SMART_TV_USB2 26 +#define EM2820_BOARD_PINNACLE_USB_2_FM1216ME 27 +#define EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE 28 +#define EM2820_BOARD_PINNACLE_DVC_100 29 +#define EM2820_BOARD_VIDEOLOGY_20K14XUSB 30 +#define EM2821_BOARD_USBGEAR_VD204 31 +#define EM2821_BOARD_SUPERCOMP_USB_2 32 +#define EM2821_BOARD_PROLINK_PLAYTV_USB2 33 +#define EM2860_BOARD_TERRATEC_HYBRID_XS 34 +#define EM2860_BOARD_TYPHOON_DVD_MAKER 35 +#define EM2860_BOARD_NETGMBH_CAM 36 +#define EM2860_BOARD_GADMEI_UTV330 37 +#define EM2861_BOARD_YAKUMO_MOVIE_MIXER 38 +#define EM2861_BOARD_KWORLD_PVRTV_300U 39 +#define EM2861_BOARD_PLEXTOR_PX_TV100U 40 +#define EM2870_BOARD_KWORLD_350U 41 +#define EM2870_BOARD_KWORLD_355U 42 +#define EM2870_BOARD_TERRATEC_XS 43 +#define EM2870_BOARD_TERRATEC_XS_MT2060 44 +#define EM2870_BOARD_PINNACLE_PCTV_DVB 45 +#define EM2870_BOARD_COMPRO_VIDEOMATE 46 +#define EM2880_BOARD_KWORLD_DVB_305U 47 +#define EM2880_BOARD_KWORLD_DVB_310U 48 +#define EM2880_BOARD_MSI_DIGIVOX_AD 49 +#define EM2880_BOARD_MSI_DIGIVOX_AD_II 50 +#define EM2880_BOARD_TERRATEC_HYBRID_XS_FR 51 +#define EM2881_BOARD_DNT_DA2_HYBRID 52 +#define EM2881_BOARD_PINNACLE_HYBRID_PRO 53 +#define EM2882_BOARD_KWORLD_VS_DVBT 54 +#define EM2882_BOARD_TERRATEC_HYBRID_XS 55 +#define EM2882_BOARD_PINNACLE_HYBRID_PRO 56 +#define EM2883_BOARD_KWORLD_HYBRID_A316 57 +#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 58 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 #define EM28XX_DEF_BUF 8 +/* Params for validated field */ +#define EM28XX_BOARD_NOT_VALIDATED 1 +#define EM28XX_BOARD_VALIDATED 0 + /* maximum number of em28xx boards */ #define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */ @@ -253,6 +294,7 @@ struct em28xx_board { unsigned int max_range_640_480:1; unsigned int has_dvb:1; unsigned int has_snapshot_button:1; + unsigned int valid:1; enum em28xx_decoder decoder; @@ -333,6 +375,7 @@ struct em28xx { unsigned int max_range_640_480:1; unsigned int has_dvb:1; unsigned int has_snapshot_button:1; + unsigned int valid:1; /* report for validated boards */ /* Some older em28xx chips needs a waiting time after writing */ unsigned int wait_after_write; @@ -362,7 +405,7 @@ struct em28xx { v4l2_std_id norm; /* selected tv norm */ int ctl_freq; /* selected frequency */ unsigned int ctl_input; /* selected input */ - unsigned int ctl_ainput; /* slected audio input */ + unsigned int ctl_ainput;/* selected audio input */ int mute; int volume; /* frame properties */ -- cgit v1.2.3 From d3603341e2f3c39f017f8df4b1cd734aeb0d453b Mon Sep 17 00:00:00 2001 From: Vitaly Wool Date: Sun, 27 Jul 2008 14:10:11 -0300 Subject: V4L/DVB (8540): em28xx-cards: Add Compro VideoMate ForYou/Stereo model Added Compro VideoMate ForYou/Stereo model (analog only) Signed-off-by: Vitaly Wool [dougsland@gmail.com: Solved conflicts with v4l-dvb devel tree] Signed-off-by: Douglas Schilling Landgraf [mchehab@infradead.org: Need to fix some merge conflicts] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 18 ++++++++++++++++++ drivers/media/video/em28xx/em28xx.h | 1 + 2 files changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index e3e965defd5..766b0bed7e7 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -1134,6 +1134,22 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, + [EM2820_BOARD_COMPRO_VIDEO_MATE] = { + .name = "Compro VideoMate ForYou/Stereo", + .vchannels = 2, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); @@ -1195,6 +1211,8 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, { USB_DEVICE(0x185b, 0x2870), .driver_info = EM2870_BOARD_COMPRO_VIDEOMATE }, + { USB_DEVICE(0x185b, 0x2041), + .driver_info = EM2820_BOARD_COMPRO_VIDEO_MATE }, { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, { USB_DEVICE(0x2040, 0x4201), diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 1b7364d664b..746a7acaf9d 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -97,6 +97,7 @@ #define EM2882_BOARD_PINNACLE_HYBRID_PRO 56 #define EM2883_BOARD_KWORLD_HYBRID_A316 57 #define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 58 +#define EM2820_BOARD_COMPRO_VIDEO_MATE 59 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 -- cgit v1.2.3 From 10ac6603613d46a43a4544fbbe9581e50879bd45 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 27 Jul 2008 14:58:58 -0300 Subject: V4L/DVB (8541): em28xx: HVR-950 entry is duplicated. Thanks to "Devin Heitmueller" for pointing this issue. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 37 +++++++------------------------ drivers/media/video/em28xx/em28xx-dvb.c | 2 +- drivers/media/video/em28xx/em28xx.h | 5 ++--- 3 files changed, 11 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 766b0bed7e7..2064f720337 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -606,7 +606,7 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, - [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950] = { + [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950] = { .name = "Hauppauge WinTV HVR 950", .vchannels = 3, .tda9887_conf = TDA9887_PRESENT, @@ -1093,26 +1093,6 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, - [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950] = { - .name = "Hauppauge WinTV HVR 950", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, [EM2883_BOARD_KWORLD_HYBRID_A316] = { .name = "Kworld PlusTV HD Hybrid 330", .valid = EM28XX_BOARD_NOT_VALIDATED, @@ -1222,13 +1202,13 @@ struct usb_device_id em28xx_id_table [] = { { USB_DEVICE(0x2040, 0x6502), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 }, { USB_DEVICE(0x2040, 0x6513), /* HCW HVR-980 */ - .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, + .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, { USB_DEVICE(0x2040, 0x6517), /* HP HVR-950 */ - .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, + .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, { USB_DEVICE(0x2040, 0x651b), /* RP HVR-950 */ - .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, + .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, { USB_DEVICE(0x2040, 0x651f), /* HCW HVR-850 */ - .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, + .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, { USB_DEVICE(0x0438, 0xb002), .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, { USB_DEVICE(0x2001, 0xf112), @@ -1401,10 +1381,9 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: case EM2860_BOARD_TERRATEC_HYBRID_XS: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: case EM2882_BOARD_PINNACLE_HYBRID_PRO: - case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2883_BOARD_KWORLD_HYBRID_A316: case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); @@ -1595,7 +1574,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) /* djh - Not sure which demod we need here */ ctl->demod = XC3028_FE_DEFAULT; break; - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: /* FIXME: Better to specify the needed IF */ @@ -1778,7 +1757,7 @@ void em28xx_card_setup(struct em28xx *dev) case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: { struct tveeprom tv; #ifdef CONFIG_MODULES diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index 31475a24571..4b992bc0083 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -410,7 +410,7 @@ static int dvb_init(struct em28xx *dev) em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); /* init frontend */ switch (dev->model) { - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: dvb->frontend = dvb_attach(lgdt330x_attach, diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 746a7acaf9d..dc2019a844e 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -54,7 +54,7 @@ #define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 #define EM2820_BOARD_PROLINK_PLAYTV_USB2 14 #define EM2800_BOARD_VGEAR_POCKETTV 15 -#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16 +#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 16 #define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17 #define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18 #define EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA 19 @@ -96,8 +96,7 @@ #define EM2882_BOARD_TERRATEC_HYBRID_XS 55 #define EM2882_BOARD_PINNACLE_HYBRID_PRO 56 #define EM2883_BOARD_KWORLD_HYBRID_A316 57 -#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 58 -#define EM2820_BOARD_COMPRO_VIDEO_MATE 59 +#define EM2820_BOARD_COMPRO_VIDEO_MATE 58 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 -- cgit v1.2.3 From fe43ef894c282dbfa963872eef577bab46a178fb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 27 Jul 2008 15:00:23 -0300 Subject: V4L/DVB (8542): em28xx: AMD ATI TV Wonder HD 600 entry at cards struct is duplicated Thanks to "Devin Heitmueller" for pointing this issue. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 2064f720337..6b241cc6c41 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -675,29 +675,6 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, - [EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = { - .name = "AMD ATI TV Wonder HD 600", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .mts_firmware = 1, - .has_12mhz_i2s = 1, - .has_dvb = 1, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, [EM2880_BOARD_TERRATEC_HYBRID_XS] = { .name = "Terratec Hybrid XS", .vchannels = 3, -- cgit v1.2.3 From ee281b856d4e4921da24387ab116bb0855c2efaa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 27 Jul 2008 16:58:04 -0300 Subject: V4L/DVB (8543): em28xx: Rename #define for Compro VideoMate ForYou/Stereo There are two videomate boards supporded by em28xx. The names are almost identical. This patch renames one of such entries to something else. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 4 ++-- drivers/media/video/em28xx/em28xx.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 6b241cc6c41..476ae44a62d 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -1091,7 +1091,7 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, - [EM2820_BOARD_COMPRO_VIDEO_MATE] = { + [EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU] = { .name = "Compro VideoMate ForYou/Stereo", .vchannels = 2, .tuner_type = TUNER_LG_PAL_NEW_TAPC, @@ -1169,7 +1169,7 @@ struct usb_device_id em28xx_id_table [] = { { USB_DEVICE(0x185b, 0x2870), .driver_info = EM2870_BOARD_COMPRO_VIDEOMATE }, { USB_DEVICE(0x185b, 0x2041), - .driver_info = EM2820_BOARD_COMPRO_VIDEO_MATE }, + .driver_info = EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU }, { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, { USB_DEVICE(0x2040, 0x4201), diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index dc2019a844e..9a331074868 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -96,7 +96,7 @@ #define EM2882_BOARD_TERRATEC_HYBRID_XS 55 #define EM2882_BOARD_PINNACLE_HYBRID_PRO 56 #define EM2883_BOARD_KWORLD_HYBRID_A316 57 -#define EM2820_BOARD_COMPRO_VIDEO_MATE 58 +#define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 -- cgit v1.2.3 From ee56a4d3e39c2baafd06aaf26d975a7c9b05e3a2 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Sun, 27 Jul 2008 14:01:59 -0300 Subject: V4L/DVB (8544): gspca: probe/open race. The device is flagged present after it is registered. During that window calls to open() that should work fail with -ENODEV. Reversing the order fixes the race. Signed-off-by: Oliver Neukum Acked-by: Hans de Goede Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index bc301bae048..3a051c925ff 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -1758,6 +1758,7 @@ int gspca_dev_probe(struct usb_interface *intf, memcpy(&gspca_dev->fops, &dev_fops, sizeof gspca_dev->fops); gspca_dev->vdev.fops = &gspca_dev->fops; gspca_dev->fops.owner = module; /* module protection */ + gspca_dev->present = 1; ret = video_register_device(&gspca_dev->vdev, VFL_TYPE_GRABBER, video_nr); @@ -1766,7 +1767,6 @@ int gspca_dev_probe(struct usb_interface *intf, goto out; } - gspca_dev->present = 1; usb_set_intfdata(intf, gspca_dev); PDEBUG(D_PROBE, "probe ok"); return 0; -- cgit v1.2.3 From 429e90893c9ad2c266d541c94d6ca69a34a7701d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 27 Jul 2008 14:08:54 -0300 Subject: V4L/DVB (8546): saa7146: fix read from uninitialized memory The offset field of the scatterlist entry *after* the last valid scatterlist entry was used instead of the first scatterlist entry (as was the intention of this code). This worked fine until the kzalloc of the sglist was replaced with kmalloc and sg_init_table only zeroed the exact needed length. Apparently kzalloc zeroes a bit more than is strictly necessary so the offset field was always 0 in the past. But now the offset field was suddenly random and this led to broken captures. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index acaddc15dad..e8bc7abf240 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -656,7 +656,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu /* if we have a user buffer, the first page may not be aligned to a page boundary. */ - pt1->offset = list->offset; + pt1->offset = dma->sglist->offset; pt2->offset = pt1->offset+o1; pt3->offset = pt1->offset+o2; -- cgit v1.2.3 From 38413fd2d82b0e75ae0492518f1b80a5cfd81956 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 27 Jul 2008 19:02:30 -0300 Subject: V4L/DVB (8548): pwc: Fix compilation Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pwc/pwc.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index 835db149a3b..74178754b39 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From f3409f71a76838b1bc985f753eed787a3f17bc2c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 27 Jul 2008 19:30:46 -0300 Subject: V4L/DVB (8549): mxl5007: Fix an error at include file mxl5007 was forcing for its compilation: In file included from drivers/media/common/tuners/mxl5007t.c:25:drivers/media/common/tuners/mxl5007t.h:80:1: warning: "CONFIG_MEDIA_TUNER_MXL5007T" redefined In file included from :0: ./include/linux/autoconf.h:2782:1: warning: this is the location of the previous definition Probably, some temporary hack for testing. Cc: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/mxl5007t.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/mxl5007t.h b/drivers/media/common/tuners/mxl5007t.h index a1ee3628b7f..aa3eea0b526 100644 --- a/drivers/media/common/tuners/mxl5007t.h +++ b/drivers/media/common/tuners/mxl5007t.h @@ -77,7 +77,6 @@ struct mxl5007t_config { unsigned int clk_out_enable:1; }; -#define CONFIG_MEDIA_TUNER_MXL5007T #if defined(CONFIG_MEDIA_TUNER_MXL5007T) || (defined(CONFIG_MEDIA_TUNER_MXL5007T_MODULE) && defined(MODULE)) extern struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 addr, -- cgit v1.2.3 From 9b1a4d38373a5581a4e01032a3ccdd94cd93477b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 28 Jul 2008 12:16:30 -0500 Subject: stop_machine: Wean existing callers off stop_machine_run() Signed-off-by: Rusty Russell --- drivers/char/hw_random/intel-rng.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c index 27fdc086649..8a2fce0756e 100644 --- a/drivers/char/hw_random/intel-rng.c +++ b/drivers/char/hw_random/intel-rng.c @@ -241,7 +241,7 @@ static int __init intel_rng_hw_init(void *_intel_rng_hw) struct intel_rng_hw *intel_rng_hw = _intel_rng_hw; u8 mfc, dvc; - /* interrupts disabled in stop_machine_run call */ + /* interrupts disabled in stop_machine call */ if (!(intel_rng_hw->fwh_dec_en1_val & FWH_F8_EN_MASK)) pci_write_config_byte(intel_rng_hw->dev, @@ -365,10 +365,10 @@ static int __init mod_init(void) * location with the Read ID command, all activity on the system * must be stopped until the state is back to normal. * - * Use stop_machine_run because IPIs can be blocked by disabling + * Use stop_machine because IPIs can be blocked by disabling * interrupts. */ - err = stop_machine_run(intel_rng_hw_init, intel_rng_hw, NR_CPUS); + err = stop_machine(intel_rng_hw_init, intel_rng_hw, NULL); pci_dev_put(dev); iounmap(intel_rng_hw->mem); kfree(intel_rng_hw); -- cgit v1.2.3 From c713e7cbfa529f87e18bb2eacb2ccdd4ee0ef7d3 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 28 Jul 2008 02:14:24 +1000 Subject: ibmveth: Fix multiple errors with dma_mapping_error conversion The addition of an argument to dma_mapping_error() in commit 8d8bb39b9eba32dd70e87fd5ad5c5dd4ba118e06 "dma-mapping: add the device argument to dma_mapping_error()" left a bit of fallout: drivers/net/ibmveth.c:263: error: too few arguments to function 'dma_mapping_error' drivers/net/ibmveth.c:264: error: expected ')' before 'goto' drivers/net/ibmveth.c:284: error: expected expression before '}' token drivers/net/ibmveth.c:297: error: too few arguments to function 'dma_mapping_error' drivers/net/ibmveth.c:298: error: expected ')' before 'dma_unmap_single' drivers/net/ibmveth.c:306: error: expected expression before '}' token drivers/net/ibmveth.c:491: error: too few arguments to function 'dma_mapping_error' drivers/net/ibmveth.c:927: error: too few arguments to function 'dma_mapping_error' drivers/net/ibmveth.c:927: error: expected ')' before '{' token drivers/net/ibmveth.c:974: error: expected expression before '}' token drivers/net/ibmveth.c:914: error: label 'out' used but not defined m Signed-off-by: Stephen Rothwell Signed-off-by: Benjamin Herrenschmidt --- drivers/net/ibmveth.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 91ec9fdc718..a03fe1fb61c 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -260,7 +260,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc dma_addr = dma_map_single(&adapter->vdev->dev, skb->data, pool->buff_size, DMA_FROM_DEVICE); - if (dma_mapping_error((&adapter->vdev->dev, dma_addr)) + if (dma_mapping_error(&adapter->vdev->dev, dma_addr)) goto failure; pool->free_map[free_index] = IBM_VETH_INVALID_MAP; @@ -294,7 +294,7 @@ failure: pool->consumer_index = pool->size - 1; else pool->consumer_index--; - if (!dma_mapping_error((&adapter->vdev->dev, dma_addr)) + if (!dma_mapping_error(&adapter->vdev->dev, dma_addr)) dma_unmap_single(&adapter->vdev->dev, pool->dma_addr[index], pool->buff_size, DMA_FROM_DEVICE); @@ -488,7 +488,7 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter) &adapter->rx_buff_pool[i]); if (adapter->bounce_buffer != NULL) { - if (!dma_mapping_error(adapter->bounce_buffer_dma)) { + if (!dma_mapping_error(dev, adapter->bounce_buffer_dma)) { dma_unmap_single(&adapter->vdev->dev, adapter->bounce_buffer_dma, adapter->netdev->mtu + IBMVETH_BUFF_OH, @@ -924,7 +924,7 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) buf[1] = 0; } - if (dma_mapping_error((&adapter->vdev->dev, data_dma_addr)) { + if (dma_mapping_error(&adapter->vdev->dev, data_dma_addr)) { if (!firmware_has_feature(FW_FEATURE_CMO)) ibmveth_error_printk("tx: unable to map xmit buffer\n"); skb_copy_from_linear_data(skb, adapter->bounce_buffer, -- cgit v1.2.3 From c63847a3621d2bac054f5709783860ecabd0ee7e Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Fri, 6 Jun 2008 17:04:08 +0900 Subject: sh: Add SCIF2 support for SH7763. SH7763 has 3 SCIF device. Current code supports SCIF0 and 1. SCIF0 and 1 are same register constitution, but only SCIF2 is different. I added support of SCIF2. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.c | 17 ++++++++++++++++- drivers/serial/sh-sci.h | 38 +++++++++++++++++++++++++++----------- 2 files changed, 43 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 208e42ba945..3df2aaec829 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -410,7 +410,6 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) #endif #if defined(CONFIG_CPU_SUBTYPE_SH7760) || \ - defined(CONFIG_CPU_SUBTYPE_SH7763) || \ defined(CONFIG_CPU_SUBTYPE_SH7780) || \ defined(CONFIG_CPU_SUBTYPE_SH7785) static inline int scif_txroom(struct uart_port *port) @@ -422,6 +421,22 @@ static inline int scif_rxroom(struct uart_port *port) { return sci_in(port, SCRFDR) & 0xff; } +#elif defined(CONFIG_CPU_SUBTYPE_SH7763) +static inline int scif_txroom(struct uart_port *port) +{ + if((port->mapbase == 0xffe00000) || (port->mapbase == 0xffe08000)) /* SCIF0/1*/ + return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0xff); + else /* SCIF2 */ + return SCIF2_TXROOM_MAX - (sci_in(port, SCFDR) >> 8); +} + +static inline int scif_rxroom(struct uart_port *port) +{ + if((port->mapbase == 0xffe00000) || (port->mapbase == 0xffe08000)) /* SCIF0/1*/ + return sci_in(port, SCRFDR) & 0xff; + else /* SCIF2 */ + return sci_in(port, SCFDR) & SCIF2_RFDC_MASK; +} #else static inline int scif_txroom(struct uart_port *port) { diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index eb84833233f..cd728df6a01 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -123,8 +123,9 @@ #elif defined(CONFIG_CPU_SUBTYPE_SH7763) # define SCSPTR0 0xffe00024 /* 16 bit SCIF */ # define SCSPTR1 0xffe08024 /* 16 bit SCIF */ +# define SCSPTR2 0xffe10020 /* 16 bit SCIF/IRDA */ # define SCIF_ORER 0x0001 /* overrun error bit */ -# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ # define SCIF_ONLY #elif defined(CONFIG_CPU_SUBTYPE_SH7770) # define SCSPTR0 0xff923020 /* 16 bit SCIF */ @@ -188,6 +189,7 @@ defined(CONFIG_CPU_SUBTYPE_SH7750S) || \ defined(CONFIG_CPU_SUBTYPE_SH7751) || \ defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ + defined(CONFIG_CPU_SUBTYPE_SH7763) || \ defined(CONFIG_CPU_SUBTYPE_SH7780) || \ defined(CONFIG_CPU_SUBTYPE_SH7785) || \ defined(CONFIG_CPU_SUBTYPE_SHX3) @@ -225,14 +227,21 @@ #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ defined(CONFIG_CPU_SUBTYPE_SH7720) || \ defined(CONFIG_CPU_SUBTYPE_SH7721) -#define SCIF_ORER 0x0200 -#define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER) -#define SCIF_RFDC_MASK 0x007f -#define SCIF_TXROOM_MAX 64 +# define SCIF_ORER 0x0200 +# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER) +# define SCIF_RFDC_MASK 0x007f +# define SCIF_TXROOM_MAX 64 +#elif defined(CONFIG_CPU_SUBTYPE_SH7763) +# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK ) +# define SCIF_RFDC_MASK 0x007f +# define SCIF_TXROOM_MAX 64 +/* SH7763 SCIF2 support */ +# define SCIF2_RFDC_MASK 0x001f +# define SCIF2_TXROOM_MAX 16 #else -#define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK) -#define SCIF_RFDC_MASK 0x001f -#define SCIF_TXROOM_MAX 16 +# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK) +# define SCIF_RFDC_MASK 0x001f +# define SCIF_TXROOM_MAX 16 #endif #if defined(SCI_ONLY) @@ -445,11 +454,16 @@ SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16) defined(CONFIG_CPU_SUBTYPE_SH7763) || \ defined(CONFIG_CPU_SUBTYPE_SH7780) || \ defined(CONFIG_CPU_SUBTYPE_SH7785) -SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16) SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16) SCIF_FNS(SCSPTR, 0, 0, 0x24, 16) SCIF_FNS(SCLSR, 0, 0, 0x28, 16) +#if defined(CONFIG_CPU_SUBTYPE_SH7763) +/* SH7763 SCIF2 */ +SCIF_FNS(SCFDR, 0, 0, 0x1C, 16) +SCIF_FNS(SCSPTR2, 0, 0, 0x20, 16) +SCIF_FNS(SCLSR2, 0, 0, 0x24, 16) +#endif /* CONFIG_CPU_SUBTYPE_SH7763 */ #else SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) #if defined(CONFIG_CPU_SUBTYPE_SH7722) @@ -652,6 +666,9 @@ static inline int sci_rxd_in(struct uart_port *port) return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ if (port->mapbase == 0xffe08000) return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xffe10000) + return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF/IRDA */ + return 1; } #elif defined(CONFIG_CPU_SUBTYPE_SH7770) @@ -764,8 +781,7 @@ static inline int sci_rxd_in(struct uart_port *port) * -- Mitch Davis - 15 Jul 2000 */ -#if defined(CONFIG_CPU_SUBTYPE_SH7763) || \ - defined(CONFIG_CPU_SUBTYPE_SH7780) || \ +#if defined(CONFIG_CPU_SUBTYPE_SH7780) || \ defined(CONFIG_CPU_SUBTYPE_SH7785) #define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1) #elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ -- cgit v1.2.3 From d3aa43a9db3b18e65f91985b5b91f2450d8b4048 Mon Sep 17 00:00:00 2001 From: Tetsuya Mukawa Date: Sat, 19 Jul 2008 07:46:53 +0900 Subject: sh_keysc: remove request_mem_region() and release_mem_region() Remove request_mem_region() and release_mem_region() from sh_keysc driver. Those functions can find resource conflict, but it is already checked in platform_device_add(). Signed-off-by: Tetsuya Mukawa Signed-off-by: Magnus Damm Signed-off-by: Andrew Morton Cc: Dmitry Torokhov Signed-off-by: Paul Mundt --- drivers/input/keyboard/sh_keysc.c | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index 8486abc457e..c600ab7f93e 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -158,25 +158,18 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev) memcpy(&priv->pdata, pdev->dev.platform_data, sizeof(priv->pdata)); pdata = &priv->pdata; - res = request_mem_region(res->start, res_size(res), pdev->name); - if (res == NULL) { - dev_err(&pdev->dev, "failed to request I/O memory\n"); - error = -EBUSY; - goto err1; - } - priv->iomem_base = ioremap_nocache(res->start, res_size(res)); if (priv->iomem_base == NULL) { dev_err(&pdev->dev, "failed to remap I/O memory\n"); error = -ENXIO; - goto err2; + goto err1; } priv->input = input_allocate_device(); if (!priv->input) { dev_err(&pdev->dev, "failed to allocate input device\n"); error = -ENOMEM; - goto err3; + goto err2; } input = priv->input; @@ -194,7 +187,7 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev) error = request_irq(irq, sh_keysc_isr, 0, pdev->name, pdev); if (error) { dev_err(&pdev->dev, "failed to request IRQ\n"); - goto err4; + goto err3; } for (i = 0; i < SH_KEYSC_MAXKEYS; i++) { @@ -206,7 +199,7 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev) error = input_register_device(input); if (error) { dev_err(&pdev->dev, "failed to register input device\n"); - goto err5; + goto err4; } iowrite16((sh_keysc_mode[pdata->mode].kymd << 8) | @@ -214,14 +207,12 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev) iowrite16(0, priv->iomem_base + KYOUTDR_OFFS); iowrite16(KYCR2_IRQ_LEVEL, priv->iomem_base + KYCR2_OFFS); return 0; - err5: - free_irq(irq, pdev); err4: - input_free_device(input); + free_irq(irq, pdev); err3: - iounmap(priv->iomem_base); + input_free_device(input); err2: - release_mem_region(res->start, res_size(res)); + iounmap(priv->iomem_base); err1: platform_set_drvdata(pdev, NULL); kfree(priv); @@ -232,7 +223,6 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev) static int __devexit sh_keysc_remove(struct platform_device *pdev) { struct sh_keysc_priv *priv = platform_get_drvdata(pdev); - struct resource *res; iowrite16(KYCR2_IRQ_DISABLED, priv->iomem_base + KYCR2_OFFS); @@ -240,9 +230,6 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev) free_irq(platform_get_irq(pdev, 0), pdev); iounmap(priv->iomem_base); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res_size(res)); - platform_set_drvdata(pdev, NULL); kfree(priv); return 0; -- cgit v1.2.3 From 7878ac81e69c5b3ccad59808da06edf16455a57a Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Mon, 28 Jul 2008 12:21:25 +0200 Subject: Remove deprecated virt_to_bus() Please pull from git://git.kernel.org/pub/scm/linux/kernel/git/kkeil/ISDN-2.6.git master This was a forgotten item in a printk from the old driver, the DMA allocation use already the new interface. Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/Kconfig | 1 - drivers/isdn/hardware/mISDN/hfcpci.c | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index 9cd5f5f6228..14793480c45 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -7,7 +7,6 @@ config MISDN_HFCPCI tristate "Support for HFC PCI cards" depends on MISDN depends on PCI - depends on VIRT_TO_BUS help Enable support for cards with Cologne Chip AG's HFC PCI chip. diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 917968530e1..3231814e7ef 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -1988,8 +1988,7 @@ setup_hw(struct hfc_pci *hc) printk(KERN_INFO "HFC-PCI: defined at mem %#lx fifo %#lx(%#lx) IRQ %d HZ %d\n", (u_long) hc->hw.pci_io, (u_long) hc->hw.fifos, - (u_long) virt_to_bus(hc->hw.fifos), - hc->irq, HZ); + (u_long) hc->hw.dmahandle, hc->irq, HZ); /* enable memory mapped ports, disable busmaster */ pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO); hc->hw.int_m2 = 0; -- cgit v1.2.3 From 399dee2371787825a1845de87c0cbee7b7c30ad6 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 28 Jul 2008 12:04:06 +0100 Subject: i2c: S3C2410: Pass the I2C bus number via drivers platform data Allow the platform data to specify the bus bumber that the new I2C bus will be given. This is to allow the use of the board registration mechanism to specify the new style of I2C device registration which allows boards to provide a list of attached devices. Note, as discussed on the mailing list, we have dropped backwards compatibility of adding an dynamic bus number as it should not affect most boards to have the bus pinned to 0 if they have either not specified platform data for driver. Any board supplying platform data will automatically have the bus_num field set to 0, and anyone who needs the driver on a different bus number can supply platform data to set bus_num. Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-s3c2410.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 007390ad981..eef35d3f607 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -752,9 +752,12 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) static int s3c24xx_i2c_probe(struct platform_device *pdev) { struct s3c24xx_i2c *i2c = &s3c24xx_i2c; + struct s3c2410_platform_i2c *pdata; struct resource *res; int ret; + pdata = s3c24xx_i2c_get_platformdata(&pdev->dev); + /* find the clock and enable it */ i2c->dev = &pdev->dev; @@ -832,7 +835,15 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "irq resource %p (%lu)\n", res, (unsigned long)res->start); - ret = i2c_add_adapter(&i2c->adap); + /* Note, previous versions of the driver used i2c_add_adapter() + * to add the bus at any number. We now pass the bus number via + * the platform data, so if unset it will now default to always + * being bus 0. + */ + + i2c->adap.nr = pdata->bus_num; + + ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) { dev_err(&pdev->dev, "failed to add bus to i2c core\n"); goto err_irq; -- cgit v1.2.3 From 1efe7c55d2c4acc6c1d1c1a68bd9070f13815272 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 28 Jul 2008 12:04:09 +0100 Subject: i2c: i2c_gpio: keep probe resident for hotplugged devices. Change the i2c_gpio driver to use platform_driver_register() instead of platform_driver_probe() to ensure that is can attach to any devices that may be loaded after it has initialised. Acked-by: Haavard Skinnemoen Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-gpio.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 79b455a1f09..32104eac8d3 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -77,7 +77,7 @@ static int i2c_gpio_getscl(void *data) return gpio_get_value(pdata->scl_pin); } -static int __init i2c_gpio_probe(struct platform_device *pdev) +static int __devinit i2c_gpio_probe(struct platform_device *pdev) { struct i2c_gpio_platform_data *pdata; struct i2c_algo_bit_data *bit_data; @@ -174,7 +174,7 @@ err_alloc_adap: return ret; } -static int __exit i2c_gpio_remove(struct platform_device *pdev) +static int __devexit i2c_gpio_remove(struct platform_device *pdev) { struct i2c_gpio_platform_data *pdata; struct i2c_adapter *adap; @@ -196,14 +196,15 @@ static struct platform_driver i2c_gpio_driver = { .name = "i2c-gpio", .owner = THIS_MODULE, }, - .remove = __exit_p(i2c_gpio_remove), + .probe = i2c_gpio_probe, + .remove = __devexit_p(i2c_gpio_remove), }; static int __init i2c_gpio_init(void) { int ret; - ret = platform_driver_probe(&i2c_gpio_driver, i2c_gpio_probe); + ret = platform_driver_register(&i2c_gpio_driver); if (ret) printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret); -- cgit v1.2.3 From 61c7cff89224fc5651b5ba5ff2185d19304b2484 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 28 Jul 2008 12:04:07 +0100 Subject: i2c: S3C24XX I2C frequency scaling support. Add support for CPU frequency scaling to the S3C24XX I2C driver. Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-s3c2410.c | 116 ++++++++++++++++++++++++++++++++++----- 1 file changed, 103 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index eef35d3f607..4864723c742 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,7 @@ struct s3c24xx_i2c { unsigned int tx_setup; enum s3c24xx_i2c_state state; + unsigned long clkrate; void __iomem *regs; struct clk *clk; @@ -71,6 +73,10 @@ struct s3c24xx_i2c { struct resource *irq; struct resource *ioarea; struct i2c_adapter adap; + +#ifdef CONFIG_CPU_FREQ + struct notifier_block freq_transition; +#endif }; /* default platform data to use if not supplied in the platform_device @@ -501,6 +507,9 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int unsigned long timeout; int ret; + if (!readl(i2c->regs + S3C2410_IICCON) & S3C2410_IICCON_IRQEN) + return -EIO; + ret = s3c24xx_i2c_set_master(i2c); if (ret != 0) { dev_err(i2c->dev, "cannot get bus (error %d)\n", ret); @@ -636,27 +645,28 @@ static inline int freq_acceptable(unsigned int freq, unsigned int wanted) return (diff >= -2 && diff <= 2); } -/* s3c24xx_i2c_getdivisor +/* s3c24xx_i2c_clockrate * * work out a divisor for the user requested frequency setting, * either by the requested frequency, or scanning the acceptable * range of frequencies until something is found */ -static int s3c24xx_i2c_getdivisor(struct s3c24xx_i2c *i2c, - struct s3c2410_platform_i2c *pdata, - unsigned long *iicon, - unsigned int *got) +static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got) { + struct s3c2410_platform_i2c *pdata; unsigned long clkin = clk_get_rate(i2c->clk); - unsigned int divs, div1; + u32 iiccon; int freq; int start, end; + i2c->clkrate = clkin; + + pdata = s3c24xx_i2c_get_platformdata(i2c->adap.dev.parent); clkin /= 1000; /* clkin now in KHz */ - dev_dbg(i2c->dev, "pdata %p, freq %lu %lu..%lu\n", + dev_dbg(i2c->dev, "pdata %p, freq %lu %lu..%lu\n", pdata, pdata->bus_freq, pdata->min_freq, pdata->max_freq); if (pdata->bus_freq != 0) { @@ -688,11 +698,79 @@ static int s3c24xx_i2c_getdivisor(struct s3c24xx_i2c *i2c, found: *got = freq; - *iicon |= (divs-1); - *iicon |= (div1 == 512) ? S3C2410_IICCON_TXDIV_512 : 0; + + iiccon = readl(i2c->regs + S3C2410_IICCON); + iiccon &= ~(S3C2410_IICCON_SCALEMASK | S3C2410_IICCON_TXDIV_512); + iiccon |= (divs-1); + + if (div1 == 512) + iiccon |= S3C2410_IICCON_TXDIV_512; + + writel(iiccon, i2c->regs + S3C2410_IICCON); + + return 0; +} + +#ifdef CONFIG_CPU_FREQ + +#define freq_to_i2c(_n) container_of(_n, struct s3c24xx_i2c, freq_transition) + +static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct s3c24xx_i2c *i2c = freq_to_i2c(nb); + unsigned long flags; + unsigned int got; + int delta_f; + int ret; + + delta_f = clk_get_rate(i2c->clk) - i2c->clkrate; + + /* if we're post-change and the input clock has slowed down + * or at pre-change and the clock is about to speed up, then + * adjust our clock rate. <0 is slow, >0 speedup. + */ + + if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) || + (val == CPUFREQ_PRECHANGE && delta_f > 0)) { + spin_lock_irqsave(&i2c->lock, flags); + ret = s3c24xx_i2c_clockrate(i2c, &got); + spin_unlock_irqrestore(&i2c->lock, flags); + + if (ret < 0) + dev_err(i2c->dev, "cannot find frequency\n"); + else + dev_info(i2c->dev, "setting freq %d\n", got); + } + return 0; } +static inline int s3c24xx_i2c_register_cpufreq(struct s3c24xx_i2c *i2c) +{ + i2c->freq_transition.notifier_call = s3c24xx_i2c_cpufreq_transition; + + return cpufreq_register_notifier(&i2c->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +} + +static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c) +{ + cpufreq_unregister_notifier(&i2c->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +} + +#else +static inline int s3c24xx_i2c_register_cpufreq(struct s3c24xx_i2c *i2c) +{ + return 0; +} + +static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c) +{ +} +#endif + /* s3c24xx_i2c_init * * initialise the controller, set the IO lines and frequency @@ -719,9 +797,12 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr); + writel(iicon, i2c->regs + S3C2410_IICCON); + /* we need to work out the divisors for the clock... */ - if (s3c24xx_i2c_getdivisor(i2c, pdata, &iicon, &freq) != 0) { + if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) { + writel(0, i2c->regs + S3C2410_IICCON); dev_err(i2c->dev, "cannot meet bus frequency required\n"); return -EINVAL; } @@ -730,8 +811,6 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq); dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon); - - writel(iicon, i2c->regs + S3C2410_IICCON); /* check for s3c2440 i2c controller */ @@ -835,6 +914,12 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "irq resource %p (%lu)\n", res, (unsigned long)res->start); + ret = s3c24xx_i2c_register_cpufreq(i2c); + if (ret < 0) { + dev_err(&pdev->dev, "failed to register cpufreq notifier\n"); + goto err_irq; + } + /* Note, previous versions of the driver used i2c_add_adapter() * to add the bus at any number. We now pass the bus number via * the platform data, so if unset it will now default to always @@ -846,7 +931,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) { dev_err(&pdev->dev, "failed to add bus to i2c core\n"); - goto err_irq; + goto err_cpufreq; } platform_set_drvdata(pdev, i2c); @@ -854,6 +939,9 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) dev_info(&pdev->dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id); return 0; + err_cpufreq: + s3c24xx_i2c_deregister_cpufreq(i2c); + err_irq: free_irq(i2c->irq->start, i2c); @@ -881,6 +969,8 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) { struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); + s3c24xx_i2c_deregister_cpufreq(i2c); + i2c_del_adapter(&i2c->adap); free_irq(i2c->irq->start, i2c); -- cgit v1.2.3 From 958585f58f675a3c2855c7d91b6fdd2875552d0b Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Sun, 27 Jul 2008 14:41:54 +0800 Subject: i2c: Blackfin I2C Driver: Functional power management support PM_SUSPEND_MEM: Blackfin does not maintain register state through Hibernate. Save and restore peripheral base initialization during PM transitions. Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-bfin-twi.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 48d084bdf7c..3c855ff2992 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -49,6 +49,8 @@ struct bfin_twi_iface { struct i2c_msg *pmsg; int msg_num; int cur_msg; + u16 saved_clkdiv; + u16 saved_control; void __iomem *regs_base; }; @@ -565,32 +567,43 @@ static u32 bfin_twi_functionality(struct i2c_adapter *adap) I2C_FUNC_I2C; } - static struct i2c_algorithm bfin_twi_algorithm = { .master_xfer = bfin_twi_master_xfer, .smbus_xfer = bfin_twi_smbus_xfer, .functionality = bfin_twi_functionality, }; - -static int i2c_bfin_twi_suspend(struct platform_device *dev, pm_message_t state) +static int i2c_bfin_twi_suspend(struct platform_device *pdev, pm_message_t state) { - struct bfin_twi_iface *iface = platform_get_drvdata(dev); + struct bfin_twi_iface *iface = platform_get_drvdata(pdev); + + iface->saved_clkdiv = read_CLKDIV(iface); + iface->saved_control = read_CONTROL(iface); + + free_irq(iface->irq, iface); /* Disable TWI */ - write_CONTROL(iface, read_CONTROL(iface) & ~TWI_ENA); - SSYNC(); + write_CONTROL(iface, iface->saved_control & ~TWI_ENA); return 0; } -static int i2c_bfin_twi_resume(struct platform_device *dev) +static int i2c_bfin_twi_resume(struct platform_device *pdev) { - struct bfin_twi_iface *iface = platform_get_drvdata(dev); + struct bfin_twi_iface *iface = platform_get_drvdata(pdev); - /* Enable TWI */ - write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA); - SSYNC(); + int rc = request_irq(iface->irq, bfin_twi_interrupt_entry, + IRQF_DISABLED, pdev->name, iface); + if (rc) { + dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq); + return -ENODEV; + } + + /* Resume TWI interface clock as specified */ + write_CLKDIV(iface, iface->saved_clkdiv); + + /* Resume TWI */ + write_CONTROL(iface, iface->saved_control); return 0; } -- cgit v1.2.3 From 7485d26b7e13ee8ff82adb271ac90a996c1fe830 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 24 Jul 2008 18:36:37 +0200 Subject: cpm_uart: Modem control lines support This patch replaces the get_mctrl/set_mctrl stubs with modem control line read/write access through the GPIO lib. Available modem control lines are described in the device tree using GPIO bindings. The driver expect a GPIO pin for each of the CTS, RTS, DCD, DSR, DTR and RI signals. Unused control lines can be left out. Signed-off-by: Laurent Pinchart Signed-off-by: Kumar Gala --- drivers/serial/cpm_uart/cpm_uart.h | 10 +++++++++ drivers/serial/cpm_uart/cpm_uart_core.c | 40 ++++++++++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h index 5c76e0ae058..5999ef5ac78 100644 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ b/drivers/serial/cpm_uart/cpm_uart.h @@ -50,6 +50,15 @@ #define SCC_WAIT_CLOSING 100 +#define GPIO_CTS 0 +#define GPIO_RTS 1 +#define GPIO_DCD 2 +#define GPIO_DSR 3 +#define GPIO_DTR 4 +#define GPIO_RI 5 + +#define NUM_GPIOS (GPIO_RI+1) + struct uart_cpm_port { struct uart_port port; u16 rx_nrfifos; @@ -82,6 +91,7 @@ struct uart_cpm_port { int wait_closing; /* value to combine with opcode to form cpm command */ u32 command; + int gpios[NUM_GPIOS]; }; extern int cpm_uart_nr; diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index a4f86927a74..5e0c17f7165 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include #include @@ -96,13 +98,41 @@ static unsigned int cpm_uart_tx_empty(struct uart_port *port) static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { - /* Whee. Do nothing. */ + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + + if (pinfo->gpios[GPIO_RTS] >= 0) + gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS)); + + if (pinfo->gpios[GPIO_DTR] >= 0) + gpio_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR)); } static unsigned int cpm_uart_get_mctrl(struct uart_port *port) { - /* Whee. Do nothing. */ - return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; + struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + + if (pinfo->gpios[GPIO_CTS] >= 0) { + if (gpio_get_value(pinfo->gpios[GPIO_CTS])) + mctrl &= ~TIOCM_CTS; + } + + if (pinfo->gpios[GPIO_DSR] >= 0) { + if (gpio_get_value(pinfo->gpios[GPIO_DSR])) + mctrl &= ~TIOCM_DSR; + } + + if (pinfo->gpios[GPIO_DCD] >= 0) { + if (gpio_get_value(pinfo->gpios[GPIO_DCD])) + mctrl &= ~TIOCM_CAR; + } + + if (pinfo->gpios[GPIO_RI] >= 0) { + if (!gpio_get_value(pinfo->gpios[GPIO_RI])) + mctrl |= TIOCM_RNG; + } + + return mctrl; } /* @@ -991,6 +1021,7 @@ static int cpm_uart_init_port(struct device_node *np, void __iomem *mem, *pram; int len; int ret; + int i; data = of_get_property(np, "fsl,cpm-brg", &len); if (!data || len != 4) { @@ -1050,6 +1081,9 @@ static int cpm_uart_init_port(struct device_node *np, goto out_pram; } + for (i = 0; i < NUM_GPIOS; i++) + pinfo->gpios[i] = of_get_gpio(np, i); + return cpm_uart_request_port(&pinfo->port); out_pram: -- cgit v1.2.3 From 80776554b6c93cf828ddc702010c6a189aa0d0e9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 28 Jul 2008 10:42:16 +0200 Subject: cpm_uart: Add generic clock API support to set baudrates This patch introduces baudrate setting support via the generic clock API. When present the optional device tree clock property is used instead of fsl-cpm-brg. Platforms can then define complex clock schemes, to output the serial clock on an external pin for instance. Signed-off-by: Laurent Pinchart Signed-off-by: Kumar Gala --- drivers/serial/cpm_uart/cpm_uart.h | 1 + drivers/serial/cpm_uart/cpm_uart_core.c | 26 +++++++++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h index 5999ef5ac78..7274b527a3c 100644 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ b/drivers/serial/cpm_uart/cpm_uart.h @@ -77,6 +77,7 @@ struct uart_cpm_port { unsigned char *rx_buf; u32 flags; void (*set_lineif)(struct uart_cpm_port *); + struct clk *clk; u8 brg; uint dp_addr; void *mem_addr; diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index 5e0c17f7165..25efca5a7a1 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -596,7 +597,10 @@ static void cpm_uart_set_termios(struct uart_port *port, out_be16(&sccp->scc_psmr, (sbits << 12) | scval); } - cpm_set_brg(pinfo->brg - 1, baud); + if (pinfo->clk) + clk_set_rate(pinfo->clk, baud); + else + cpm_set_brg(pinfo->brg - 1, baud); spin_unlock_irqrestore(&port->lock, flags); } @@ -1023,13 +1027,21 @@ static int cpm_uart_init_port(struct device_node *np, int ret; int i; - data = of_get_property(np, "fsl,cpm-brg", &len); - if (!data || len != 4) { - printk(KERN_ERR "CPM UART %s has no/invalid " - "fsl,cpm-brg property.\n", np->name); - return -EINVAL; + data = of_get_property(np, "clock", NULL); + if (data) { + struct clk *clk = clk_get(NULL, (const char*)data); + if (!IS_ERR(clk)) + pinfo->clk = clk; + } + if (!pinfo->clk) { + data = of_get_property(np, "fsl,cpm-brg", &len); + if (!data || len != 4) { + printk(KERN_ERR "CPM UART %s has no/invalid " + "fsl,cpm-brg property.\n", np->name); + return -EINVAL; + } + pinfo->brg = *data; } - pinfo->brg = *data; data = of_get_property(np, "fsl,cpm-command", &len); if (!data || len != 4) { -- cgit v1.2.3 From 0e09c863dbb8b1816ebc106df1a1cae4c588ce0e Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Mon, 28 Jul 2008 16:37:10 +0200 Subject: pcmcia: rsrc_nonstatic: check value, not pointer Bug found by Harvey Harrison and Stephen Rothwell. Signed-off-by: Dominik Brodowski --- drivers/pcmcia/rsrc_nonstatic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index d0c1d63d189..203e579ebbd 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -275,7 +275,7 @@ static int readable(struct pcmcia_socket *s, struct resource *res, destroy_cis_cache(s); } s->cis_mem.res = NULL; - if ((ret != 0) || (count == 0)) + if ((ret != 0) || (*count == 0)) return 0; return 1; } -- cgit v1.2.3 From 00eabe7c4478f38b42d632763c4878ced5a1f25c Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 28 Jul 2008 11:59:20 +0900 Subject: [SCSI] qla2xxx: fix msleep compile error drivers/scsi/qla2xxx/qla_attr.c: In function 'qla24xx_vport_delete': drivers/scsi/qla2xxx/qla_attr.c:1184: error: implicit declaration of function 'msleep' make[3]: *** [drivers/scsi/qla2xxx/qla_attr.o] Error 1 make[3]: *** Waiting for unfinished jobs.... Reported-by: David Miller Signed-off-by: FUJITA Tomonori Acked-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 7a4409ab30e..a319a20ed44 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -8,6 +8,7 @@ #include #include +#include static int qla24xx_vport_disable(struct fc_vport *, bool); -- cgit v1.2.3 From d4c0deb7009217d5cf7d0fe89255d64ecfad932b Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 28 Jul 2008 16:52:33 +0200 Subject: ipwireless: Misc cleanups ipwireless: Misc cleanups - remove likely() and some extra () in ifs - use unsigned in for loops - remove useless typecasts - remove obvious comments - add () around ?: Signed-off-by: David Sterba Signed-off-by: Jiri Kosina Signed-off-by: Linus Torvalds --- drivers/char/pcmcia/ipwireless/hardware.c | 50 +++++++++++-------------------- 1 file changed, 18 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c index 929101ecbae..6a3e666af01 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.c +++ b/drivers/char/pcmcia/ipwireless/hardware.c @@ -389,7 +389,7 @@ static void dump_data_bytes(const char *type, const unsigned char *data, static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data, unsigned length) { - int i; + unsigned i; unsigned long flags; start_timing(); @@ -414,7 +414,7 @@ static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data, unsigned short d = data[i]; __le16 raw_data; - if (likely(i + 1 < length)) + if (i + 1 < length) d |= data[i + 1] << 8; raw_data = cpu_to_le16(d); outw(raw_data, hw->base_port + IODWR); @@ -428,7 +428,7 @@ static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data, unsigned short d = data[i]; __le16 raw_data; - if ((i + 1 < length)) + if (i + 1 < length) d |= data[i + 1] << 8; raw_data = cpu_to_le16(d); outw(raw_data, hw->base_port + IODMADPR); @@ -549,12 +549,7 @@ static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw, if (!packet) { unsigned long flags; - /* - * If this is the first fragment, then we will need to fetch a - * packet to put it in. - */ spin_lock_irqsave(&hw->spinlock, flags); - /* If we have one in our pool, then pull it out. */ if (!list_empty(&hw->rx_pool)) { packet = list_first_entry(&hw->rx_pool, struct ipw_rx_packet, queue); @@ -562,15 +557,14 @@ static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw, hw->rx_pool_size--; spin_unlock_irqrestore(&hw->spinlock, flags); } else { - /* Otherwise allocate a new one. */ static int min_capacity = 256; int new_capacity; spin_unlock_irqrestore(&hw->spinlock, flags); new_capacity = - minimum_free_space > min_capacity - ? minimum_free_space - : min_capacity; + (minimum_free_space > min_capacity + ? minimum_free_space + : min_capacity); packet = kmalloc(sizeof(struct ipw_rx_packet) + new_capacity, GFP_ATOMIC); if (!packet) @@ -580,10 +574,6 @@ static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw, packet->length = 0; } - /* - * If this packet does not have sufficient capacity for the data we - * want to add, then make it bigger. - */ if (packet->length + minimum_free_space > packet->capacity) { struct ipw_rx_packet *old_packet = packet; @@ -686,7 +676,7 @@ static void queue_received_packet(struct ipw_hardware *hw, list_add_tail(&packet->queue, &hw->rx_queue); /* Block reception of incoming packets if queue is full. */ hw->blocking_rx = - hw->rx_bytes_queued >= IPWIRELESS_RX_QUEUE_SIZE; + (hw->rx_bytes_queued >= IPWIRELESS_RX_QUEUE_SIZE); spin_unlock_irqrestore(&hw->spinlock, flags); schedule_work(&hw->work_rx); @@ -850,7 +840,7 @@ static void acknowledge_data_read(struct ipw_hardware *hw) static void do_receive_packet(struct ipw_hardware *hw) { unsigned len; - unsigned int i; + unsigned i; unsigned char pkt[LL_MTU_MAX]; start_timing(); @@ -916,8 +906,7 @@ static int get_current_packet_priority(struct ipw_hardware *hw) * until setup is complete. */ return (hw->to_setup || hw->initializing - ? PRIO_SETUP + 1 : - NL_NUM_OF_PRIORITIES); + ? PRIO_SETUP + 1 : NL_NUM_OF_PRIORITIES); } /* @@ -1128,9 +1117,8 @@ static irqreturn_t ipwireless_handle_v2_v3_interrupt(int irq, } else { return IRQ_NONE; } - } else { + } else return IRQ_NONE; - } } /* @@ -1297,15 +1285,14 @@ int ipwireless_send_packet(struct ipw_hardware *hw, unsigned int channel_idx, { struct ipw_tx_packet *packet; - packet = alloc_data_packet(length, - (unsigned char) (channel_idx + 1), - TL_PROTOCOLID_COM_DATA); + packet = alloc_data_packet(length, (channel_idx + 1), + TL_PROTOCOLID_COM_DATA); if (!packet) return -ENOMEM; packet->packet_callback = callback; packet->callback_data = callback_data; - memcpy((unsigned char *) packet + - sizeof(struct ipw_tx_packet), data, length); + memcpy((unsigned char *) packet + sizeof(struct ipw_tx_packet), data, + length); send_packet(hw, PRIO_DATA, packet); return 0; @@ -1321,12 +1308,11 @@ static int set_control_line(struct ipw_hardware *hw, int prio, protocolid = TL_PROTOCOLID_SETUP; packet = alloc_ctrl_packet(sizeof(struct ipw_control_packet), - (unsigned char) (channel_idx + 1), - protocolid, line); + (channel_idx + 1), protocolid, line); if (!packet) return -ENOMEM; packet->header.length = sizeof(struct ipw_control_packet_body); - packet->body.value = (unsigned char) (state == 0 ? 0 : 1); + packet->body.value = (state == 0 ? 0 : 1); send_packet(hw, prio, &packet->header); return 0; } @@ -1651,8 +1637,8 @@ void ipwireless_init_hardware_v1(struct ipw_hardware *hw, enable_irq(hw->irq); } hw->base_port = base_port; - hw->hw_version = is_v2_card ? HW_VERSION_2 : HW_VERSION_1; - hw->ll_mtu = hw->hw_version == HW_VERSION_1 ? LL_MTU_V1 : LL_MTU_V2; + hw->hw_version = (is_v2_card ? HW_VERSION_2 : HW_VERSION_1); + hw->ll_mtu = (hw->hw_version == HW_VERSION_1 ? LL_MTU_V1 : LL_MTU_V2); hw->memregs_CCR = (struct MEMCCR __iomem *) ((unsigned short __iomem *) attr_memory + 0x200); hw->memory_info_regs = (struct MEMINFREG __iomem *) common_memory; -- cgit v1.2.3 From 2e713165f892c833d240cb265ab35490a7ef456f Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 28 Jul 2008 16:52:39 +0200 Subject: ipwireless: Remove unused defines ipwireless: Remove unused defines Remove unused defines, defines hiding variables, defines hiding 0. Signed-off-by: David Sterba Signed-off-by: Jiri Kosina Signed-off-by: Linus Torvalds --- drivers/char/pcmcia/ipwireless/hardware.c | 15 ++++++--------- drivers/char/pcmcia/ipwireless/network.c | 3 +-- 2 files changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c index 6a3e666af01..ce57a7f92e8 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.c +++ b/drivers/char/pcmcia/ipwireless/hardware.c @@ -227,15 +227,12 @@ struct MEMINFREG { unsigned short memreg_tx_new; /* TX2 (new) Register (R/W) */ }; -#define IODMADPR 0x00 /* DMA Data Port Register (R/W) */ - #define CARD_PRESENT_VALUE (0xBEEFCAFEUL) #define MEMTX_TX 0x0001 #define MEMRX_RX 0x0001 #define MEMRX_RX_DONE 0x0001 #define MEMRX_PCINTACKK 0x0001 -#define MEMRX_MEMSPURIOUSINT 0x0001 #define NL_NUM_OF_PRIORITIES 3 #define NL_NUM_OF_PROTOCOLS 3 @@ -422,7 +419,7 @@ static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data, outw(DCR_TXDONE, hw->base_port + IODCR); } else if (hw->hw_version == HW_VERSION_2) { - outw((unsigned short) length, hw->base_port + IODMADPR); + outw((unsigned short) length, hw->base_port); for (i = 0; i < length; i += 2) { unsigned short d = data[i]; @@ -431,10 +428,10 @@ static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data, if (i + 1 < length) d |= data[i + 1] << 8; raw_data = cpu_to_le16(d); - outw(raw_data, hw->base_port + IODMADPR); + outw(raw_data, hw->base_port); } while ((i & 3) != 2) { - outw((unsigned short) 0xDEAD, hw->base_port + IODMADPR); + outw((unsigned short) 0xDEAD, hw->base_port); i += 2; } writew(MEMRX_RX, &hw->memory_info_regs->memreg_rx); @@ -863,7 +860,7 @@ static void do_receive_packet(struct ipw_hardware *hw) pkt[i + 1] = (unsigned char) (data >> 8); } } else { - len = inw(hw->base_port + IODMADPR); + len = inw(hw->base_port); if (len > hw->ll_mtu) { printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": received a packet of %u bytes - " @@ -874,7 +871,7 @@ static void do_receive_packet(struct ipw_hardware *hw) } for (i = 0; i < len; i += 2) { - __le16 raw_data = inw(hw->base_port + IODMADPR); + __le16 raw_data = inw(hw->base_port); unsigned short data = le16_to_cpu(raw_data); pkt[i] = (unsigned char) data; @@ -882,7 +879,7 @@ static void do_receive_packet(struct ipw_hardware *hw) } while ((i & 3) != 2) { - inw(hw->base_port + IODMADPR); + inw(hw->base_port); i += 2; } } diff --git a/drivers/char/pcmcia/ipwireless/network.c b/drivers/char/pcmcia/ipwireless/network.c index fe914d34f7f..cf12eb400f9 100644 --- a/drivers/char/pcmcia/ipwireless/network.c +++ b/drivers/char/pcmcia/ipwireless/network.c @@ -29,7 +29,6 @@ #include "main.h" #include "tty.h" -#define MAX_OUTGOING_PACKETS_QUEUED ipwireless_out_queue #define MAX_ASSOCIATED_TTYS 2 #define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) @@ -94,7 +93,7 @@ static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel, unsigned long flags; spin_lock_irqsave(&network->spinlock, flags); - if (network->outgoing_packets_queued < MAX_OUTGOING_PACKETS_QUEUED) { + if (network->outgoing_packets_queued < ipwireless_out_queue) { unsigned char *buf; static unsigned char header[] = { PPP_ALLSTATIONS, /* 0xff */ -- cgit v1.2.3 From 63c4dbd1023b9acd516d71635b06741962cc8a0f Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 28 Jul 2008 16:52:44 +0200 Subject: ipwireless: Rename spinlock variables to lock ipwireless: Rename spinlock variables to lock Signed-off-by: David Sterba Signed-off-by: Jiri Kosina Signed-off-by: Linus Torvalds --- drivers/char/pcmcia/ipwireless/hardware.c | 96 +++++++++++++++---------------- drivers/char/pcmcia/ipwireless/network.c | 46 +++++++-------- 2 files changed, 71 insertions(+), 71 deletions(-) (limited to 'drivers') diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c index ce57a7f92e8..f948791c929 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.c +++ b/drivers/char/pcmcia/ipwireless/hardware.c @@ -242,7 +242,7 @@ struct ipw_hardware { unsigned int base_port; short hw_version; unsigned short ll_mtu; - spinlock_t spinlock; + spinlock_t lock; int initializing; int init_loops; @@ -400,7 +400,7 @@ static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data, if (ipwireless_debug) dump_data_bytes("send", data, length); - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); hw->tx_ready = 0; @@ -437,7 +437,7 @@ static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data, writew(MEMRX_RX, &hw->memory_info_regs->memreg_rx); } - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); end_write_timing(length); @@ -490,10 +490,10 @@ static int do_send_packet(struct ipw_hardware *hw, struct ipw_tx_packet *packet) */ unsigned long flags; - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); list_add(&packet->queue, &hw->tx_queue[0]); hw->tx_queued++; - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); } else { if (packet->packet_callback) packet->packet_callback(packet->callback_data, @@ -508,7 +508,7 @@ static void ipw_setup_hardware(struct ipw_hardware *hw) { unsigned long flags; - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); if (hw->hw_version == HW_VERSION_1) { /* Reset RX FIFO */ outw(DCR_RXRESET, hw->base_port + IODCR); @@ -527,7 +527,7 @@ static void ipw_setup_hardware(struct ipw_hardware *hw) csr |= 1; writew(csr, &hw->memregs_CCR->reg_config_and_status); } - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); } /* @@ -546,18 +546,18 @@ static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw, if (!packet) { unsigned long flags; - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); if (!list_empty(&hw->rx_pool)) { packet = list_first_entry(&hw->rx_pool, struct ipw_rx_packet, queue); list_del(&packet->queue); hw->rx_pool_size--; - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); } else { static int min_capacity = 256; int new_capacity; - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); new_capacity = (minimum_free_space > min_capacity ? minimum_free_space @@ -645,9 +645,9 @@ static void queue_received_packet(struct ipw_hardware *hw, packet = *assem; *assem = NULL; /* Count queued DATA bytes only */ - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); hw->rx_bytes_queued += packet->length; - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); } } else { /* If it's a CTRL packet, don't assemble, just queue it. */ @@ -669,13 +669,13 @@ static void queue_received_packet(struct ipw_hardware *hw, * network layer. */ if (packet) { - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); list_add_tail(&packet->queue, &hw->rx_queue); /* Block reception of incoming packets if queue is full. */ hw->blocking_rx = (hw->rx_bytes_queued >= IPWIRELESS_RX_QUEUE_SIZE); - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); schedule_work(&hw->work_rx); } } @@ -689,7 +689,7 @@ static void ipw_receive_data_work(struct work_struct *work_rx) container_of(work_rx, struct ipw_hardware, work_rx); unsigned long flags; - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); while (!list_empty(&hw->rx_queue)) { struct ipw_rx_packet *packet = list_first_entry(&hw->rx_queue, @@ -707,7 +707,7 @@ static void ipw_receive_data_work(struct work_struct *work_rx) if (packet->protocol == TL_PROTOCOLID_COM_DATA) { if (hw->network != NULL) { /* If the network hasn't been disconnected. */ - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); /* * This must run unlocked due to tty processing * and mutex locking @@ -718,7 +718,7 @@ static void ipw_receive_data_work(struct work_struct *work_rx) (unsigned char *)packet + sizeof(struct ipw_rx_packet), packet->length); - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); } /* Count queued DATA bytes only */ hw->rx_bytes_queued -= packet->length; @@ -742,7 +742,7 @@ static void ipw_receive_data_work(struct work_struct *work_rx) if (hw->shutting_down) break; } - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); } static void handle_received_CTRL_packet(struct ipw_hardware *hw, @@ -914,17 +914,17 @@ static int get_packets_from_hw(struct ipw_hardware *hw) int received = 0; unsigned long flags; - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); while (hw->rx_ready && !hw->blocking_rx) { received = 1; hw->rx_ready--; - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); do_receive_packet(hw); - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); } - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); return received; } @@ -940,7 +940,7 @@ static int send_pending_packet(struct ipw_hardware *hw, int priority_limit) int more_to_send = 0; unsigned long flags; - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); if (hw->tx_queued && hw->tx_ready) { int priority; struct ipw_tx_packet *packet = NULL; @@ -961,17 +961,17 @@ static int send_pending_packet(struct ipw_hardware *hw, int priority_limit) } if (!packet) { hw->tx_queued = 0; - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); return 0; } - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); /* Send */ do_send_packet(hw, packet); /* Check if more to send */ - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); for (priority = 0; priority < priority_limit; priority++) if (!list_empty(&hw->tx_queue[priority])) { more_to_send = 1; @@ -981,7 +981,7 @@ static int send_pending_packet(struct ipw_hardware *hw, int priority_limit) if (!more_to_send) hw->tx_queued = 0; } - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); return more_to_send; } @@ -994,9 +994,9 @@ static void ipwireless_do_tasklet(unsigned long hw_) struct ipw_hardware *hw = (struct ipw_hardware *) hw_; unsigned long flags; - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); if (hw->shutting_down) { - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); return; } @@ -1005,7 +1005,7 @@ static void ipwireless_do_tasklet(unsigned long hw_) * Initial setup data sent to hardware */ hw->to_setup = 2; - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); ipw_setup_hardware(hw); ipw_send_setup_packet(hw); @@ -1016,7 +1016,7 @@ static void ipwireless_do_tasklet(unsigned long hw_) int priority_limit = get_current_packet_priority(hw); int again; - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); do { again = send_pending_packet(hw, priority_limit); @@ -1054,16 +1054,16 @@ static irqreturn_t ipwireless_handle_v1_interrupt(int irq, /* Transmit complete. */ if (irqn & IR_TXINTR) { ack |= IR_TXINTR; - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); hw->tx_ready = 1; - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); } /* Received data */ if (irqn & IR_RXINTR) { ack |= IR_RXINTR; - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); hw->rx_ready++; - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); } if (ack != 0) { outw(ack, hw->base_port + IOIR); @@ -1134,9 +1134,9 @@ static irqreturn_t ipwireless_handle_v2_v3_interrupt(int irq, if (hw->serial_number_detected) { if (memtx_serial != hw->last_memtx_serial) { hw->last_memtx_serial = memtx_serial; - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); hw->rx_ready++; - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); rx = 1; } else /* Ignore 'Timer Recovery' duplicates. */ @@ -1151,18 +1151,18 @@ static irqreturn_t ipwireless_handle_v2_v3_interrupt(int irq, printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": memreg_tx serial num detected\n"); - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); hw->rx_ready++; - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); } rx = 1; } } if (memrxdone & MEMRX_RX_DONE) { writew(0, &hw->memory_info_regs->memreg_rx_done); - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); hw->tx_ready = 1; - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); tx = 1; } if (tx) @@ -1211,9 +1211,9 @@ static void flush_packets_to_hw(struct ipw_hardware *hw) int priority_limit; unsigned long flags; - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); priority_limit = get_current_packet_priority(hw); - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); while (send_pending_packet(hw, priority_limit)); } @@ -1223,10 +1223,10 @@ static void send_packet(struct ipw_hardware *hw, int priority, { unsigned long flags; - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); list_add_tail(&packet->queue, &hw->tx_queue[priority]); hw->tx_queued++; - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); flush_packets_to_hw(hw); } @@ -1612,7 +1612,7 @@ struct ipw_hardware *ipwireless_hardware_create(void) INIT_LIST_HEAD(&hw->rx_queue); INIT_LIST_HEAD(&hw->rx_pool); - spin_lock_init(&hw->spinlock); + spin_lock_init(&hw->lock); tasklet_init(&hw->tasklet, ipwireless_do_tasklet, (unsigned long) hw); INIT_WORK(&hw->work_rx, ipw_receive_data_work); setup_timer(&hw->setup_timer, ipwireless_setup_timer, @@ -1678,10 +1678,10 @@ static void ipwireless_setup_timer(unsigned long data) if (is_card_present(hw)) { unsigned long flags; - spin_lock_irqsave(&hw->spinlock, flags); + spin_lock_irqsave(&hw->lock, flags); hw->to_setup = 1; hw->tx_ready = 1; - spin_unlock_irqrestore(&hw->spinlock, flags); + spin_unlock_irqrestore(&hw->lock, flags); tasklet_schedule(&hw->tasklet); } diff --git a/drivers/char/pcmcia/ipwireless/network.c b/drivers/char/pcmcia/ipwireless/network.c index cf12eb400f9..28d9fd727d8 100644 --- a/drivers/char/pcmcia/ipwireless/network.c +++ b/drivers/char/pcmcia/ipwireless/network.c @@ -45,7 +45,7 @@ struct ipw_network { /* Number of packets queued up in hardware module. */ int outgoing_packets_queued; /* Spinlock to avoid interrupts during shutdown */ - spinlock_t spinlock; + spinlock_t lock; struct mutex close_lock; /* PPP ioctl data, not actually used anywere */ @@ -67,20 +67,20 @@ static void notify_packet_sent(void *callback_data, unsigned int packet_length) struct ipw_network *network = callback_data; unsigned long flags; - spin_lock_irqsave(&network->spinlock, flags); + spin_lock_irqsave(&network->lock, flags); network->outgoing_packets_queued--; if (network->ppp_channel != NULL) { if (network->ppp_blocked) { network->ppp_blocked = 0; - spin_unlock_irqrestore(&network->spinlock, flags); + spin_unlock_irqrestore(&network->lock, flags); ppp_output_wakeup(network->ppp_channel); if (ipwireless_debug) printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": ppp unblocked\n"); } else - spin_unlock_irqrestore(&network->spinlock, flags); + spin_unlock_irqrestore(&network->lock, flags); } else - spin_unlock_irqrestore(&network->spinlock, flags); + spin_unlock_irqrestore(&network->lock, flags); } /* @@ -92,7 +92,7 @@ static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel, struct ipw_network *network = ppp_channel->private; unsigned long flags; - spin_lock_irqsave(&network->spinlock, flags); + spin_lock_irqsave(&network->lock, flags); if (network->outgoing_packets_queued < ipwireless_out_queue) { unsigned char *buf; static unsigned char header[] = { @@ -102,7 +102,7 @@ static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel, int ret; network->outgoing_packets_queued++; - spin_unlock_irqrestore(&network->spinlock, flags); + spin_unlock_irqrestore(&network->lock, flags); /* * If we have the requested amount of headroom in the skb we @@ -143,7 +143,7 @@ static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel, * needs to be unblocked once we are ready to send. */ network->ppp_blocked = 1; - spin_unlock_irqrestore(&network->spinlock, flags); + spin_unlock_irqrestore(&network->lock, flags); return 0; } } @@ -248,11 +248,11 @@ static void do_go_online(struct work_struct *work_go_online) work_go_online); unsigned long flags; - spin_lock_irqsave(&network->spinlock, flags); + spin_lock_irqsave(&network->lock, flags); if (!network->ppp_channel) { struct ppp_channel *channel; - spin_unlock_irqrestore(&network->spinlock, flags); + spin_unlock_irqrestore(&network->lock, flags); channel = kzalloc(sizeof(struct ppp_channel), GFP_KERNEL); if (!channel) { printk(KERN_ERR IPWIRELESS_PCCARD_NAME @@ -272,10 +272,10 @@ static void do_go_online(struct work_struct *work_go_online) network->xaccm[3] = 0x60000000U; network->raccm = ~0U; ppp_register_channel(channel); - spin_lock_irqsave(&network->spinlock, flags); + spin_lock_irqsave(&network->lock, flags); network->ppp_channel = channel; } - spin_unlock_irqrestore(&network->spinlock, flags); + spin_unlock_irqrestore(&network->lock, flags); } static void do_go_offline(struct work_struct *work_go_offline) @@ -286,16 +286,16 @@ static void do_go_offline(struct work_struct *work_go_offline) unsigned long flags; mutex_lock(&network->close_lock); - spin_lock_irqsave(&network->spinlock, flags); + spin_lock_irqsave(&network->lock, flags); if (network->ppp_channel != NULL) { struct ppp_channel *channel = network->ppp_channel; network->ppp_channel = NULL; - spin_unlock_irqrestore(&network->spinlock, flags); + spin_unlock_irqrestore(&network->lock, flags); mutex_unlock(&network->close_lock); ppp_unregister_channel(channel); } else { - spin_unlock_irqrestore(&network->spinlock, flags); + spin_unlock_irqrestore(&network->lock, flags); mutex_unlock(&network->close_lock); } } @@ -380,18 +380,18 @@ void ipwireless_network_packet_received(struct ipw_network *network, * the PPP layer. */ mutex_lock(&network->close_lock); - spin_lock_irqsave(&network->spinlock, flags); + spin_lock_irqsave(&network->lock, flags); if (network->ppp_channel != NULL) { struct sk_buff *skb; - spin_unlock_irqrestore(&network->spinlock, + spin_unlock_irqrestore(&network->lock, flags); /* Send the data to the ppp_generic module. */ skb = ipw_packet_received_skb(data, length); ppp_input(network->ppp_channel, skb); } else - spin_unlock_irqrestore(&network->spinlock, + spin_unlock_irqrestore(&network->lock, flags); mutex_unlock(&network->close_lock); } @@ -409,7 +409,7 @@ struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw) if (!network) return NULL; - spin_lock_init(&network->spinlock); + spin_lock_init(&network->lock); mutex_init(&network->close_lock); network->hardware = hw; @@ -477,10 +477,10 @@ int ipwireless_ppp_channel_index(struct ipw_network *network) int ret = -1; unsigned long flags; - spin_lock_irqsave(&network->spinlock, flags); + spin_lock_irqsave(&network->lock, flags); if (network->ppp_channel != NULL) ret = ppp_channel_index(network->ppp_channel); - spin_unlock_irqrestore(&network->spinlock, flags); + spin_unlock_irqrestore(&network->lock, flags); return ret; } @@ -490,10 +490,10 @@ int ipwireless_ppp_unit_number(struct ipw_network *network) int ret = -1; unsigned long flags; - spin_lock_irqsave(&network->spinlock, flags); + spin_lock_irqsave(&network->lock, flags); if (network->ppp_channel != NULL) ret = ppp_unit_number(network->ppp_channel); - spin_unlock_irqrestore(&network->spinlock, flags); + spin_unlock_irqrestore(&network->lock, flags); return ret; } -- cgit v1.2.3 From 2fc5577e1729ac303ad8b9547f8ccdb057076998 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 28 Jul 2008 16:52:49 +0200 Subject: ipwireless: Remove pt_regs from interrupt handler ipwireless: Remove pt_regs from interrupt handler Signed-off-by: David Sterba Signed-off-by: Jiri Kosina Signed-off-by: Linus Torvalds --- drivers/char/pcmcia/ipwireless/hardware.c | 2 +- drivers/char/pcmcia/ipwireless/hardware.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c index f948791c929..0ccbbc1f593 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.c +++ b/drivers/char/pcmcia/ipwireless/hardware.c @@ -1196,7 +1196,7 @@ static irqreturn_t ipwireless_handle_v2_v3_interrupt(int irq, return IRQ_HANDLED; } -irqreturn_t ipwireless_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t ipwireless_interrupt(int irq, void *dev_id) { struct ipw_hardware *hw = dev_id; diff --git a/drivers/char/pcmcia/ipwireless/hardware.h b/drivers/char/pcmcia/ipwireless/hardware.h index 19ce5eb266b..e21d23a922a 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.h +++ b/drivers/char/pcmcia/ipwireless/hardware.h @@ -34,7 +34,7 @@ struct ipw_network; struct ipw_hardware *ipwireless_hardware_create(void); void ipwireless_hardware_free(struct ipw_hardware *hw); -irqreturn_t ipwireless_interrupt(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t ipwireless_interrupt(int irq, void *dev_id); int ipwireless_set_DTR(struct ipw_hardware *hw, unsigned int channel_idx, int state); int ipwireless_set_RTS(struct ipw_hardware *hw, unsigned int channel_idx, -- cgit v1.2.3 From 622e713e8e207a99aad956bf0ebe435420fb3742 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 28 Jul 2008 16:52:55 +0200 Subject: ipwireless: Glue splitted printk strings back ipwireless: Glue splitted printk strings back Signed-off-by: David Sterba Signed-off-by: Jiri Kosina Signed-off-by: Linus Torvalds --- drivers/char/pcmcia/ipwireless/hardware.c | 15 +++++---------- drivers/char/pcmcia/ipwireless/main.c | 15 +++++++-------- 2 files changed, 12 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c index 0ccbbc1f593..7428734d08a 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.c +++ b/drivers/char/pcmcia/ipwireless/hardware.c @@ -79,8 +79,7 @@ static void report_timing(void) timing_stats.last_report_time = jiffies; if (!first) printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": %u us elapsed - read %lu bytes in %u us, " - "wrote %lu bytes in %u us\n", + ": %u us elapsed - read %lu bytes in %u us, wrote %lu bytes in %u us\n", jiffies_to_usecs(since), timing_stats.read_bytes, jiffies_to_usecs(timing_stats.read_time), @@ -846,8 +845,7 @@ static void do_receive_packet(struct ipw_hardware *hw) len = inw(hw->base_port + IODRR); if (len > hw->ll_mtu) { printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": received a packet of %u bytes - " - "longer than the MTU!\n", len); + ": received a packet of %u bytes - longer than the MTU!\n", len); outw(DCR_RXDONE | DCR_RXRESET, hw->base_port + IODCR); return; } @@ -863,8 +861,7 @@ static void do_receive_packet(struct ipw_hardware *hw) len = inw(hw->base_port); if (len > hw->ll_mtu) { printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": received a packet of %u bytes - " - "longer than the MTU!\n", len); + ": received a packet of %u bytes - longer than the MTU!\n", len); writew(MEMRX_PCINTACKK, &hw->memory_info_regs->memreg_pc_interrupt_ack); return; @@ -1180,8 +1177,7 @@ static irqreturn_t ipwireless_handle_v2_v3_interrupt(int irq, ": spurious interrupt - new_tx mode\n"); else { printk(KERN_WARNING IPWIRELESS_PCCARD_NAME - ": no valid memreg_tx value - " - "switching to the old memreg_tx\n"); + ": no valid memreg_tx value - switching to the old memreg_tx\n"); hw->memreg_tx = &hw->memory_info_regs->memreg_tx_old; try_mem_tx_old = 1; @@ -1487,8 +1483,7 @@ static void handle_setup_get_version_rsp(struct ipw_hardware *hw, if (vers_no == TL_SETUP_VERSION) __handle_setup_get_version_rsp(hw); else - printk(KERN_ERR - IPWIRELESS_PCCARD_NAME + printk(KERN_ERR IPWIRELESS_PCCARD_NAME ": invalid hardware version no %u\n", (unsigned int) vers_no); } diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c index cc7dcea2d28..6bdd11df458 100644 --- a/drivers/char/pcmcia/ipwireless/main.c +++ b/drivers/char/pcmcia/ipwireless/main.c @@ -311,14 +311,13 @@ static int config_ipwireless(struct ipw_dev *ipw) (unsigned int) link->irq.AssignedIRQ); if (ipw->attr_memory && ipw->common_memory) printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": attr memory 0x%08lx-0x%08lx, " - "common memory 0x%08lx-0x%08lx\n", - request_attr_memory.Base, - request_attr_memory.Base - + request_attr_memory.Size - 1, - request_common_memory.Base, - request_common_memory.Base - + request_common_memory.Size - 1); + ": attr memory 0x%08lx-0x%08lx, common memory 0x%08lx-0x%08lx\n", + request_attr_memory.Base, + request_attr_memory.Base + + request_attr_memory.Size - 1, + request_common_memory.Base, + request_common_memory.Base + + request_common_memory.Size - 1); ipw->network = ipwireless_network_create(ipw->hardware); if (!ipw->network) -- cgit v1.2.3 From d54c2752f6bb6cc53359dcdf6ed4fb6e5fb6440a Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 28 Jul 2008 16:53:00 +0200 Subject: ipwireless: Remove endian-dependent bitfields ipwireless: Remove endian-dependent bitfields Remove endian-dependent bitfields and use bitmasks to transform packet header bitfields from/to machine order. Signed-off-by: David Sterba Signed-off-by: Jiri Kosina Signed-off-by: Linus Torvalds --- drivers/char/pcmcia/ipwireless/hardware.c | 51 +++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c index 7428734d08a..08423ba5b9d 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.c +++ b/drivers/char/pcmcia/ipwireless/hardware.c @@ -132,29 +132,17 @@ enum { #define NL_FOLLOWING_PACKET_HEADER_SIZE 1 struct nl_first_packet_header { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned char packet_rank:2; - unsigned char address:3; - unsigned char protocol:3; -#else unsigned char protocol:3; unsigned char address:3; unsigned char packet_rank:2; -#endif unsigned char length_lsb; unsigned char length_msb; }; struct nl_packet_header { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned char packet_rank:2; - unsigned char address:3; - unsigned char protocol:3; -#else unsigned char protocol:3; unsigned char address:3; unsigned char packet_rank:2; -#endif }; /* Value of 'packet_rank' above */ @@ -382,7 +370,37 @@ static void dump_data_bytes(const char *type, const unsigned char *data, length < DUMP_MAX_BYTES ? length : DUMP_MAX_BYTES); } -static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data, +static void swap_packet_bitfield_to_le(unsigned char *data) +{ +#ifdef __BIG_ENDIAN_BITFIELD + unsigned char tmp = *data, ret = 0; + + /* + * transform bits from aa.bbb.ccc to ccc.bbb.aa + */ + ret |= tmp & 0xc0 >> 6; + ret |= tmp & 0x38 >> 1; + ret |= tmp & 0x07 << 5; + *data = ret & 0xff; +#endif +} + +static void swap_packet_bitfield_from_le(unsigned char *data) +{ +#ifdef __BIG_ENDIAN_BITFIELD + unsigned char tmp = *data, ret = 0; + + /* + * transform bits from ccc.bbb.aa to aa.bbb.ccc + */ + ret |= tmp & 0xe0 >> 5; + ret |= tmp & 0x1c << 1; + ret |= tmp & 0x03 << 6; + *data = ret & 0xff; +#endif +} + +static int do_send_fragment(struct ipw_hardware *hw, unsigned char *data, unsigned length) { unsigned i; @@ -402,6 +420,7 @@ static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data, spin_lock_irqsave(&hw->lock, flags); hw->tx_ready = 0; + swap_packet_bitfield_to_le(data); if (hw->hw_version == HW_VERSION_1) { outw((unsigned short) length, hw->base_port + IODWR); @@ -458,6 +477,10 @@ static int do_send_packet(struct ipw_hardware *hw, struct ipw_tx_packet *packet) if (data_left < fragment_data_len) fragment_data_len = data_left; + /* + * hdr_first is now in machine bitfield order, which will be swapped + * to le just before it goes to hw + */ pkt.hdr_first.protocol = packet->protocol; pkt.hdr_first.address = packet->dest_addr; pkt.hdr_first.packet_rank = 0; @@ -883,6 +906,8 @@ static void do_receive_packet(struct ipw_hardware *hw) acknowledge_data_read(hw); + swap_packet_bitfield_from_le(pkt); + if (ipwireless_debug) dump_data_bytes("recv", pkt, len); -- cgit v1.2.3 From 93110f698fe92fc4dfd86c78783aedf522c69eb9 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 28 Jul 2008 16:53:05 +0200 Subject: ipwireless: Do not return value from sending funcs ipwireless: Do not return value from sending funcs Do not return value from do_send_fragment and do_send_packet, it's not used. The packet size checks are not useful too: * zero length packet will never be sent, caller always passes packet_header size which is either 1 or 3 * MTU check is done in caller, no need to repeat Signed-off-by: David Sterba Signed-off-by: Jiri Kosina Signed-off-by: Linus Torvalds --- drivers/char/pcmcia/ipwireless/hardware.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c index 08423ba5b9d..ff2093d2210 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.c +++ b/drivers/char/pcmcia/ipwireless/hardware.c @@ -400,19 +400,14 @@ static void swap_packet_bitfield_from_le(unsigned char *data) #endif } -static int do_send_fragment(struct ipw_hardware *hw, unsigned char *data, +static void do_send_fragment(struct ipw_hardware *hw, unsigned char *data, unsigned length) { unsigned i; unsigned long flags; start_timing(); - - if (length == 0) - return 0; - - if (length > hw->ll_mtu) - return -1; + BUG_ON(length > hw->ll_mtu); if (ipwireless_debug) dump_data_bytes("send", data, length); @@ -458,11 +453,9 @@ static int do_send_fragment(struct ipw_hardware *hw, unsigned char *data, spin_unlock_irqrestore(&hw->lock, flags); end_write_timing(length); - - return 0; } -static int do_send_packet(struct ipw_hardware *hw, struct ipw_tx_packet *packet) +static void do_send_packet(struct ipw_hardware *hw, struct ipw_tx_packet *packet) { unsigned short fragment_data_len; unsigned short data_left = packet->length - packet->offset; @@ -522,8 +515,6 @@ static int do_send_packet(struct ipw_hardware *hw, struct ipw_tx_packet *packet) packet->length); kfree(packet); } - - return 0; } static void ipw_setup_hardware(struct ipw_hardware *hw) -- cgit v1.2.3 From ff3e990e61a5a9124687a01a025c43b3564f82ab Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 28 Jul 2008 16:53:11 +0200 Subject: ipwireless: Constify buffer variables ipwireless: Constify buffer variables Signed-off-by: David Sterba Signed-off-by: Jiri Kosina Signed-off-by: Linus Torvalds --- drivers/char/pcmcia/ipwireless/hardware.c | 26 ++++++++++++++------------ drivers/char/pcmcia/ipwireless/hardware.h | 2 +- drivers/char/pcmcia/ipwireless/tty.c | 2 +- 3 files changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c index ff2093d2210..814ea3228ca 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.c +++ b/drivers/char/pcmcia/ipwireless/hardware.c @@ -30,11 +30,11 @@ static void ipw_send_setup_packet(struct ipw_hardware *hw); static void handle_received_SETUP_packet(struct ipw_hardware *ipw, unsigned int address, - unsigned char *data, int len, + const unsigned char *data, int len, int is_last); static void ipwireless_setup_timer(unsigned long data); static void handle_received_CTRL_packet(struct ipw_hardware *hw, - unsigned int channel_idx, unsigned char *data, int len); + unsigned int channel_idx, const unsigned char *data, int len); /*#define TIMING_DIAGNOSTICS*/ @@ -615,8 +615,10 @@ static void pool_free(struct ipw_hardware *hw, struct ipw_rx_packet *packet) } static void queue_received_packet(struct ipw_hardware *hw, - unsigned int protocol, unsigned int address, - unsigned char *data, int length, int is_last) + unsigned int protocol, + unsigned int address, + const unsigned char *data, int length, + int is_last) { unsigned int channel_idx = address - 1; struct ipw_rx_packet *packet = NULL; @@ -760,10 +762,10 @@ static void ipw_receive_data_work(struct work_struct *work_rx) static void handle_received_CTRL_packet(struct ipw_hardware *hw, unsigned int channel_idx, - unsigned char *data, int len) + const unsigned char *data, int len) { - struct ipw_control_packet_body *body = - (struct ipw_control_packet_body *) data; + const struct ipw_control_packet_body *body = + (const struct ipw_control_packet_body *) data; unsigned int changed_mask; if (len != sizeof(struct ipw_control_packet_body)) { @@ -805,13 +807,13 @@ static void handle_received_CTRL_packet(struct ipw_hardware *hw, } static void handle_received_packet(struct ipw_hardware *hw, - union nl_packet *packet, + const union nl_packet *packet, unsigned short len) { unsigned int protocol = packet->hdr.protocol; unsigned int address = packet->hdr.address; unsigned int header_length; - unsigned char *data; + const unsigned char *data; unsigned int data_len; int is_last = packet->hdr.packet_rank & NL_LAST_PACKET; @@ -1288,7 +1290,7 @@ static void *alloc_ctrl_packet(int header_size, } int ipwireless_send_packet(struct ipw_hardware *hw, unsigned int channel_idx, - unsigned char *data, unsigned int length, + const unsigned char *data, unsigned int length, void (*callback) (void *cb, unsigned int length), void *callback_data) { @@ -1522,10 +1524,10 @@ static void ipw_send_setup_packet(struct ipw_hardware *hw) static void handle_received_SETUP_packet(struct ipw_hardware *hw, unsigned int address, - unsigned char *data, int len, + const unsigned char *data, int len, int is_last) { - union ipw_setup_rx_msg *rx_msg = (union ipw_setup_rx_msg *) data; + const union ipw_setup_rx_msg *rx_msg = (const union ipw_setup_rx_msg *) data; if (address != ADDR_SETUP_PROT) { printk(KERN_INFO IPWIRELESS_PCCARD_NAME diff --git a/drivers/char/pcmcia/ipwireless/hardware.h b/drivers/char/pcmcia/ipwireless/hardware.h index e21d23a922a..90a8590e43b 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.h +++ b/drivers/char/pcmcia/ipwireless/hardware.h @@ -41,7 +41,7 @@ int ipwireless_set_RTS(struct ipw_hardware *hw, unsigned int channel_idx, int state); int ipwireless_send_packet(struct ipw_hardware *hw, unsigned int channel_idx, - unsigned char *data, + const unsigned char *data, unsigned int length, void (*packet_sent_callback) (void *cb, unsigned int length), diff --git a/drivers/char/pcmcia/ipwireless/tty.c b/drivers/char/pcmcia/ipwireless/tty.c index 42f3815c5ce..b1414507997 100644 --- a/drivers/char/pcmcia/ipwireless/tty.c +++ b/drivers/char/pcmcia/ipwireless/tty.c @@ -259,7 +259,7 @@ static int ipw_write(struct tty_struct *linux_tty, } ret = ipwireless_send_packet(tty->hardware, IPW_CHANNEL_RAS, - (unsigned char *) buf, count, + buf, count, ipw_write_packet_sent_callback, tty); if (ret == -1) { mutex_unlock(&tty->ipw_tty_mutex); -- cgit v1.2.3 From 09e491e9a780433f8734eb6efb7293b2da690131 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 28 Jul 2008 16:53:16 +0200 Subject: ipwireless: Explicitly request io and mem regions ipwireless: Explicitly request io and mem regions Documentation/pcmcia/driver-changes.txt says, that driver should call request_region for used memory/io regions since PCMCIA does not do this (since 2.6.8). Signed-off-by: David Sterba Signed-off-by: Jiri Kosina Signed-off-by: Linus Torvalds --- drivers/char/pcmcia/ipwireless/main.c | 79 ++++++++++++++++++++--------------- drivers/char/pcmcia/ipwireless/main.h | 5 +++ 2 files changed, 50 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c index 6bdd11df458..7169a0d3379 100644 --- a/drivers/char/pcmcia/ipwireless/main.c +++ b/drivers/char/pcmcia/ipwireless/main.c @@ -88,8 +88,6 @@ static int config_ipwireless(struct ipw_dev *ipw) unsigned short buf[64]; cisparse_t parse; unsigned short cor_value; - win_req_t request_attr_memory; - win_req_t request_common_memory; memreq_t memreq_attr_memory; memreq_t memreq_common_memory; @@ -188,6 +186,9 @@ static int config_ipwireless(struct ipw_dev *ipw) goto exit0; } + request_region(link->io.BasePort1, link->io.NumPorts1, + IPWIRELESS_PCCARD_NAME); + /* memory settings */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; @@ -214,16 +215,16 @@ static int config_ipwireless(struct ipw_dev *ipw) } if (parse.cftable_entry.mem.nwin > 0) { - request_common_memory.Attributes = + ipw->request_common_memory.Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE; - request_common_memory.Base = + ipw->request_common_memory.Base = parse.cftable_entry.mem.win[0].host_addr; - request_common_memory.Size = parse.cftable_entry.mem.win[0].len; - if (request_common_memory.Size < 0x1000) - request_common_memory.Size = 0x1000; - request_common_memory.AccessSpeed = 0; + ipw->request_common_memory.Size = parse.cftable_entry.mem.win[0].len; + if (ipw->request_common_memory.Size < 0x1000) + ipw->request_common_memory.Size = 0x1000; + ipw->request_common_memory.AccessSpeed = 0; - ret = pcmcia_request_window(&link, &request_common_memory, + ret = pcmcia_request_window(&link, &ipw->request_common_memory, &ipw->handle_common_memory); if (ret != CS_SUCCESS) { @@ -246,16 +247,18 @@ static int config_ipwireless(struct ipw_dev *ipw) ipw->is_v2_card = parse.cftable_entry.mem.win[0].len == 0x100; - ipw->common_memory = ioremap(request_common_memory.Base, - request_common_memory.Size); + ipw->common_memory = ioremap(ipw->request_common_memory.Base, + ipw->request_common_memory.Size); + request_mem_region(ipw->request_common_memory.Base, + ipw->request_common_memory.Size, IPWIRELESS_PCCARD_NAME); - request_attr_memory.Attributes = + ipw->request_attr_memory.Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE; - request_attr_memory.Base = 0; - request_attr_memory.Size = 0; /* this used to be 0x1000 */ - request_attr_memory.AccessSpeed = 0; + ipw->request_attr_memory.Base = 0; + ipw->request_attr_memory.Size = 0; /* this used to be 0x1000 */ + ipw->request_attr_memory.AccessSpeed = 0; - ret = pcmcia_request_window(&link, &request_attr_memory, + ret = pcmcia_request_window(&link, &ipw->request_attr_memory, &ipw->handle_attr_memory); if (ret != CS_SUCCESS) { @@ -274,8 +277,10 @@ static int config_ipwireless(struct ipw_dev *ipw) goto exit2; } - ipw->attr_memory = ioremap(request_attr_memory.Base, - request_attr_memory.Size); + ipw->attr_memory = ioremap(ipw->request_attr_memory.Base, + ipw->request_attr_memory.Size); + request_mem_region(ipw->request_attr_memory.Base, ipw->request_attr_memory.Size, + IPWIRELESS_PCCARD_NAME); } INIT_WORK(&ipw->work_reboot, signalled_reboot_work); @@ -312,12 +317,12 @@ static int config_ipwireless(struct ipw_dev *ipw) if (ipw->attr_memory && ipw->common_memory) printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": attr memory 0x%08lx-0x%08lx, common memory 0x%08lx-0x%08lx\n", - request_attr_memory.Base, - request_attr_memory.Base - + request_attr_memory.Size - 1, - request_common_memory.Base, - request_common_memory.Base - + request_common_memory.Size - 1); + ipw->request_attr_memory.Base, + ipw->request_attr_memory.Base + + ipw->request_attr_memory.Size - 1, + ipw->request_common_memory.Base, + ipw->request_common_memory.Base + + ipw->request_common_memory.Size - 1); ipw->network = ipwireless_network_create(ipw->hardware); if (!ipw->network) @@ -349,12 +354,16 @@ exit4: pcmcia_disable_device(link); exit3: if (ipw->attr_memory) { + release_mem_region(ipw->request_attr_memory.Base, + ipw->request_attr_memory.Size); iounmap(ipw->attr_memory); pcmcia_release_window(ipw->handle_attr_memory); pcmcia_disable_device(link); } exit2: if (ipw->common_memory) { + release_mem_region(ipw->request_common_memory.Base, + ipw->request_common_memory.Size); iounmap(ipw->common_memory); pcmcia_release_window(ipw->handle_common_memory); } @@ -366,19 +375,25 @@ exit0: static void release_ipwireless(struct ipw_dev *ipw) { - struct pcmcia_device *link = ipw->link; - - pcmcia_disable_device(link); + pcmcia_disable_device(ipw->link); - if (ipw->common_memory) + if (ipw->common_memory) { + release_mem_region(ipw->request_common_memory.Base, + ipw->request_common_memory.Size); iounmap(ipw->common_memory); - if (ipw->attr_memory) + } + if (ipw->attr_memory) { + release_mem_region(ipw->request_attr_memory.Base, + ipw->request_attr_memory.Size); iounmap(ipw->attr_memory); + } if (ipw->common_memory) pcmcia_release_window(ipw->handle_common_memory); if (ipw->attr_memory) pcmcia_release_window(ipw->handle_attr_memory); - pcmcia_disable_device(link); + + /* Break the link with Card Services */ + pcmcia_disable_device(ipw->link); } /* @@ -436,10 +451,6 @@ static void ipwireless_detach(struct pcmcia_device *link) release_ipwireless(ipw); - /* Break the link with Card Services */ - if (link) - pcmcia_disable_device(link); - if (ipw->tty != NULL) ipwireless_tty_free(ipw->tty); if (ipw->network != NULL) diff --git a/drivers/char/pcmcia/ipwireless/main.h b/drivers/char/pcmcia/ipwireless/main.h index 1bfdcc8d47d..0e0363af9ab 100644 --- a/drivers/char/pcmcia/ipwireless/main.h +++ b/drivers/char/pcmcia/ipwireless/main.h @@ -45,10 +45,15 @@ struct ipw_tty; struct ipw_dev { struct pcmcia_device *link; int is_v2_card; + window_handle_t handle_attr_memory; void __iomem *attr_memory; + win_req_t request_attr_memory; + window_handle_t handle_common_memory; void __iomem *common_memory; + win_req_t request_common_memory; + dev_node_t nodes[2]; /* Reference to attribute memory, containing CIS data */ void *attribute_memory; -- cgit v1.2.3 From bee9c7c0773517c9f1d7931144fc8dec12233bd7 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 28 Jul 2008 16:53:21 +0200 Subject: ipwireless: Increase PPP outgoing queue size ipwireless: Increase PPP outgoing queue size Increase default size of PPP outgoing queue. Currently set to 1, which means that a packet quickly following another pushed by PPP must wait until hardware actually sends the previous and PPP has to be waken up by ppp_wakeup(). This slows down upstream. Now PPP can push more packets at once which get buffered inside driver and pushed immediatelly to hardware when previous packet is out. Experiments show that size = 10 is quite good for all connection types (GPRS/EDGE/UMTS) and gains 4 KB/sec of upload for UMTS for batch uploads. Need for higher queue size than 10 occures in only < 0.1 % of cases. Signed-off-by: David Sterba Signed-off-by: Jiri Kosina Signed-off-by: Linus Torvalds --- drivers/char/pcmcia/ipwireless/main.c | 4 ++-- drivers/char/pcmcia/ipwireless/network.c | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c index 7169a0d3379..5eca7a99afe 100644 --- a/drivers/char/pcmcia/ipwireless/main.c +++ b/drivers/char/pcmcia/ipwireless/main.c @@ -49,7 +49,7 @@ static void ipwireless_detach(struct pcmcia_device *link); /* Debug mode: more verbose, print sent/recv bytes */ int ipwireless_debug; int ipwireless_loopback; -int ipwireless_out_queue = 1; +int ipwireless_out_queue = 10; module_param_named(debug, ipwireless_debug, int, 0); module_param_named(loopback, ipwireless_loopback, int, 0); @@ -57,7 +57,7 @@ module_param_named(out_queue, ipwireless_out_queue, int, 0); MODULE_PARM_DESC(debug, "switch on debug messages [0]"); MODULE_PARM_DESC(loopback, "debug: enable ras_raw channel [0]"); -MODULE_PARM_DESC(out_queue, "debug: set size of outgoing queue [1]"); +MODULE_PARM_DESC(out_queue, "debug: set size of outgoing PPP queue [10]"); /* Executes in process context. */ static void signalled_reboot_work(struct work_struct *work_reboot) diff --git a/drivers/char/pcmcia/ipwireless/network.c b/drivers/char/pcmcia/ipwireless/network.c index 28d9fd727d8..2b07af05106 100644 --- a/drivers/char/pcmcia/ipwireless/network.c +++ b/drivers/char/pcmcia/ipwireless/network.c @@ -75,7 +75,7 @@ static void notify_packet_sent(void *callback_data, unsigned int packet_length) spin_unlock_irqrestore(&network->lock, flags); ppp_output_wakeup(network->ppp_channel); if (ipwireless_debug) - printk(KERN_INFO IPWIRELESS_PCCARD_NAME + printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": ppp unblocked\n"); } else spin_unlock_irqrestore(&network->lock, flags); @@ -144,6 +144,8 @@ static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel, */ network->ppp_blocked = 1; spin_unlock_irqrestore(&network->lock, flags); + if (ipwireless_debug) + printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": ppp blocked\n"); return 0; } } -- cgit v1.2.3 From 0f38c47a545d36da4038fec0708e6e3fbdb160b1 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 28 Jul 2008 16:53:27 +0200 Subject: ipwireless: Put packets to pool start ipwireless: Put packets to pool start Put packets to pool start, try to reuse cached memory. Signed-off-by: David Sterba Signed-off-by: Jiri Kosina Signed-off-by: Linus Torvalds --- drivers/char/pcmcia/ipwireless/hardware.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c index 814ea3228ca..d1e69de1915 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.c +++ b/drivers/char/pcmcia/ipwireless/hardware.c @@ -563,9 +563,9 @@ static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw, if (!list_empty(&hw->rx_pool)) { packet = list_first_entry(&hw->rx_pool, struct ipw_rx_packet, queue); - list_del(&packet->queue); hw->rx_pool_size--; spin_unlock_irqrestore(&hw->lock, flags); + list_del(&packet->queue); } else { static int min_capacity = 256; int new_capacity; @@ -610,7 +610,7 @@ static void pool_free(struct ipw_hardware *hw, struct ipw_rx_packet *packet) kfree(packet); else { hw->rx_pool_size++; - list_add_tail(&packet->queue, &hw->rx_pool); + list_add(&packet->queue, &hw->rx_pool); } } -- cgit v1.2.3 From a01386924874c4d6d67f8a34e66f04452c2abb69 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 28 Jul 2008 16:53:32 +0200 Subject: ipwireless: Preallocate received packet buffers with MRU size ipwireless: Preallocate received packet buffers with MRU size Packets are assembled from link size (~300 bytes) up to PPP MRU (1500 by default). Try to preallocate full size rather than repeatedly advance buffer size by 256 bytes. Signed-off-by: David Sterba Signed-off-by: Jiri Kosina Signed-off-by: Linus Torvalds --- drivers/char/pcmcia/ipwireless/hardware.c | 3 ++- drivers/char/pcmcia/ipwireless/network.c | 5 +++++ drivers/char/pcmcia/ipwireless/network.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c index d1e69de1915..7d500f82195 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.c +++ b/drivers/char/pcmcia/ipwireless/hardware.c @@ -567,7 +567,8 @@ static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw, spin_unlock_irqrestore(&hw->lock, flags); list_del(&packet->queue); } else { - static int min_capacity = 256; + const int min_capacity = + ipwireless_ppp_mru(hw->network + 2); int new_capacity; spin_unlock_irqrestore(&hw->lock, flags); diff --git a/drivers/char/pcmcia/ipwireless/network.c b/drivers/char/pcmcia/ipwireless/network.c index 2b07af05106..590762a7f21 100644 --- a/drivers/char/pcmcia/ipwireless/network.c +++ b/drivers/char/pcmcia/ipwireless/network.c @@ -499,3 +499,8 @@ int ipwireless_ppp_unit_number(struct ipw_network *network) return ret; } + +int ipwireless_ppp_mru(const struct ipw_network *network) +{ + return network->mru; +} diff --git a/drivers/char/pcmcia/ipwireless/network.h b/drivers/char/pcmcia/ipwireless/network.h index ccacd26fc7e..561f765b333 100644 --- a/drivers/char/pcmcia/ipwireless/network.h +++ b/drivers/char/pcmcia/ipwireless/network.h @@ -48,5 +48,6 @@ void ipwireless_ppp_open(struct ipw_network *net); void ipwireless_ppp_close(struct ipw_network *net); int ipwireless_ppp_channel_index(struct ipw_network *net); int ipwireless_ppp_unit_number(struct ipw_network *net); +int ipwireless_ppp_mru(const struct ipw_network *net); #endif -- cgit v1.2.3 From b032bf70df2e43149ce2b4e9a865b076c6140753 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 27 Jul 2008 23:47:12 +0200 Subject: ACPI/CPUIDLE: prevent setting pm_idle to NULL pm_idle_save resp. pm_idle_old can be NULL when the restore code in acpi_processor_cst_has_changed() resp. cpuidle_uninstall_idle_handler() is called. This can set pm_idle unconditinally to NULL, which causes the kernel to panic when calling pm_idle in the x86 idle code. This was covered by an extra check for !pm_idle in the x86 idle code, which was removed during the x86 idle code refactoring. Instead of restoring the pm_idle check in the x86 code prevent the acpi/cpuidle code to set pm_idle to NULL. Reported by: Dhaval Giani http://lkml.org/lkml/2008/7/2/309 Based on a debug patch from Ingo Molnar Signed-off-by: Thomas Gleixner Signed-off-by: Linus Torvalds --- drivers/acpi/processor_idle.c | 15 +++++++++++---- drivers/cpuidle/cpuidle.c | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index b7f2963693a..283c08f5f4d 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1332,9 +1332,15 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) if (!pr->flags.power_setup_done) return -ENODEV; - /* Fall back to the default idle loop */ - pm_idle = pm_idle_save; - synchronize_sched(); /* Relies on interrupts forcing exit from idle. */ + /* + * Fall back to the default idle loop, when pm_idle_save had + * been initialized. + */ + if (pm_idle_save) { + pm_idle = pm_idle_save; + /* Relies on interrupts forcing exit from idle. */ + synchronize_sched(); + } pr->flags.power = 0; result = acpi_processor_get_power_info(pr); @@ -1896,7 +1902,8 @@ int acpi_processor_power_exit(struct acpi_processor *pr, /* Unregister the idle handler when processor #0 is removed. */ if (pr->id == 0) { - pm_idle = pm_idle_save; + if (pm_idle_save) + pm_idle = pm_idle_save; /* * We are about to unload the current idle thread pm callback diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 5405769020a..5ce07b517c5 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -94,7 +94,7 @@ void cpuidle_install_idle_handler(void) */ void cpuidle_uninstall_idle_handler(void) { - if (enabled_devices && (pm_idle != pm_idle_old)) { + if (enabled_devices && pm_idle_old && (pm_idle != pm_idle_old)) { pm_idle = pm_idle_old; cpuidle_kick_cpus(); } -- cgit v1.2.3 From 1f07be1c31cf898e5e3708d52e38db0803c62924 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 28 Jul 2008 11:05:04 +1000 Subject: more sysdev API change fallout - drivers/base/memory.c Noticed because of this warning: drivers/base/memory.c:279: warning: initialization from incompatible pointer type Signed-off-by: Stephen Rothwell Signed-off-by: Linus Torvalds --- drivers/base/memory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 3ad49a00029..af0d175c025 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -103,7 +103,8 @@ static ssize_t show_mem_phys_index(struct sys_device *dev, /* * Show whether the section of memory is likely to be hot-removable */ -static ssize_t show_mem_removable(struct sys_device *dev, char *buf) +static ssize_t show_mem_removable(struct sys_device *dev, + struct sysdev_attribute *attr, char *buf) { unsigned long start_pfn; int ret; -- cgit v1.2.3 From 0e241ffd306c0896bb9959be7faa4d4cfcb706d9 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 24 Jul 2008 16:58:42 -0700 Subject: locking: fix mutex @key parameter kernel-doc notation Fix @key parameter to mutex_init() and one of its callers. Warning(linux-2.6.26-git11//drivers/base/class.c:210): No description found for parameter 'key' Signed-off-by: Randy Dunlap Acked-by: Greg Kroah-Hartman Signed-off-by: Ingo Molnar --- drivers/base/class.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/base/class.c b/drivers/base/class.c index 839d27cecb3..5667c2f02c5 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -198,6 +198,7 @@ static void class_create_release(struct class *cls) * class_create - create a struct class structure * @owner: pointer to the module that is to "own" this struct class * @name: pointer to a string for the name of this class. + * @key: the lock_class_key for this class; used by mutex lock debugging * * This is used to create a struct class pointer that can then be used * in calls to device_create(). -- cgit v1.2.3 From 96ee41993b5b25ee0fbde2d4dcaac1f8c5ef5cc4 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 28 Jul 2008 18:26:42 +0200 Subject: mfd: Use to_platform_device instead of container_of Convert mfd_remove_devices_fn() to use to_platform_device() instead of doing container_of(). Signed-off-by: Ben Dooks Acked-by: Dmitry Baryshkov Signed-off-by: Samuel Ortiz --- drivers/mfd/mfd-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 0454be4266c..4dc861a7ac5 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -99,8 +99,7 @@ EXPORT_SYMBOL(mfd_add_devices); static int mfd_remove_devices_fn(struct device *dev, void *unused) { - platform_device_unregister( - container_of(dev, struct platform_device, dev)); + platform_device_unregister(to_platform_device(dev)); return 0; } -- cgit v1.2.3 From 7f71ac9374fec066e428892a68db158946cee1fb Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 28 Jul 2008 18:29:09 +0200 Subject: mfd: Coding style fixes Fix some coding style fixes in the mfd core driver. Signed-off-by: Ben Dooks Signed-off-by: Samuel Ortiz --- drivers/mfd/mfd-core.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 4dc861a7ac5..50207700140 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -16,9 +16,9 @@ #include static int mfd_add_device(struct platform_device *parent, - const struct mfd_cell *cell, - struct resource *mem_base, - int irq_base) + const struct mfd_cell *cell, + struct resource *mem_base, + int irq_base) { struct resource res[cell->num_resources]; struct platform_device *pdev; @@ -75,11 +75,10 @@ fail_alloc: return ret; } -int mfd_add_devices( - struct platform_device *parent, - const struct mfd_cell *cells, int n_devs, - struct resource *mem_base, - int irq_base) +int mfd_add_devices(struct platform_device *parent, + const struct mfd_cell *cells, int n_devs, + struct resource *mem_base, + int irq_base) { int i; int ret = 0; -- cgit v1.2.3 From 56adc59d81b01ac5924f7eba6e22adc762a1e2c6 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 24 Jul 2008 16:43:43 -0700 Subject: PCI hotplug: fix typo in pcie hotplug output Comamnd->Command Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/pciehp_hpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 1323a43285d..ad27e9e225a 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -1103,7 +1103,7 @@ static inline void dbg_ctrl(struct controller *ctrl) dbg(" Power Indicator : %3s\n", PWR_LED(ctrl) ? "yes" : "no"); dbg(" Hot-Plug Surprise : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no"); dbg(" EMI Present : %3s\n", EMI(ctrl) ? "yes" : "no"); - dbg(" Comamnd Completed : %3s\n", NO_CMD_CMPL(ctrl)? "no" : "yes"); + dbg(" Command Completed : %3s\n", NO_CMD_CMPL(ctrl)? "no" : "yes"); pciehp_readw(ctrl, SLOTSTATUS, ®16); dbg("Slot Status : 0x%04x\n", reg16); pciehp_readw(ctrl, SLOTCTRL, ®16); -- cgit v1.2.3 From 37139074233a5bbec54ae01ab580e5788a248cc3 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 28 Jul 2008 11:49:26 -0700 Subject: PCI: document pci_target_state The empty kdoc was causing warnings, so provide some actual documentation. Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e9c356236d2..c95f77d6571 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1123,6 +1123,12 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) } /** + * pci_target_state - find an appropriate low power state for a given PCI dev + * @dev: PCI device + * + * Use underlying platform code to find a supported low power state for @dev. + * If the platform can't manage @dev, return the deepest state from which it + * can generate wake events, based on any available PME info. */ pci_power_t pci_target_state(struct pci_dev *dev) { -- cgit v1.2.3 From 6ac665c63dcac8fcec534a1d224ecbb8b867ad59 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Mon, 28 Jul 2008 13:38:59 -0400 Subject: PCI: rewrite PCI BAR reading code Factor out the code to read one BAR from the loop in pci_read_bases into a new function, __pci_read_base. The new code is slightly more readable, better commented and removes the ifdef. Signed-off-by: Matthew Wilcox Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 242 ++++++++++++++++++++++++++-------------------------- 1 file changed, 123 insertions(+), 119 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index b1724cf31b6..3b690c3512f 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -163,12 +163,9 @@ static inline unsigned int pci_calc_resource_flags(unsigned int flags) return IORESOURCE_MEM; } -/* - * Find the extent of a PCI decode.. - */ -static u32 pci_size(u32 base, u32 maxbase, u32 mask) +static u64 pci_size(u64 base, u64 maxbase, u64 mask) { - u32 size = mask & maxbase; /* Find the significant bits */ + u64 size = mask & maxbase; /* Find the significant bits */ if (!size) return 0; @@ -184,135 +181,142 @@ static u32 pci_size(u32 base, u32 maxbase, u32 mask) return size; } -static u64 pci_size64(u64 base, u64 maxbase, u64 mask) -{ - u64 size = mask & maxbase; /* Find the significant bits */ - if (!size) - return 0; +enum pci_bar_type { + pci_bar_unknown, /* Standard PCI BAR probe */ + pci_bar_io, /* An io port BAR */ + pci_bar_mem32, /* A 32-bit memory BAR */ + pci_bar_mem64, /* A 64-bit memory BAR */ +}; - /* Get the lowest of them to find the decode size, and - from that the extent. */ - size = (size & ~(size-1)) - 1; +static inline enum pci_bar_type decode_bar(struct resource *res, u32 bar) +{ + if ((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { + res->flags = bar & ~PCI_BASE_ADDRESS_IO_MASK; + return pci_bar_io; + } - /* base == maxbase can be valid only if the BAR has - already been programmed with all 1s. */ - if (base == maxbase && ((base | size) & mask) != mask) - return 0; + res->flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK; - return size; + if (res->flags == PCI_BASE_ADDRESS_MEM_TYPE_64) + return pci_bar_mem64; + return pci_bar_mem32; } -static inline int is_64bit_memory(u32 mask) +/* + * If the type is not unknown, we assume that the lowest bit is 'enable'. + * Returns 1 if the BAR was 64-bit and 0 if it was 32-bit. + */ +static int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, + struct resource *res, unsigned int pos) { - if ((mask & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) == - (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64)) - return 1; - return 0; -} + u32 l, sz, mask; -static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) -{ - unsigned int pos, reg, next; - u32 l, sz; - struct resource *res; + mask = type ? ~PCI_ROM_ADDRESS_ENABLE : ~0; - for(pos=0; posname = pci_name(dev); - next = pos+1; - res = &dev->resource[pos]; - res->name = pci_name(dev); - reg = PCI_BASE_ADDRESS_0 + (pos << 2); - pci_read_config_dword(dev, reg, &l); - pci_write_config_dword(dev, reg, ~0); - pci_read_config_dword(dev, reg, &sz); - pci_write_config_dword(dev, reg, l); - if (!sz || sz == 0xffffffff) - continue; - if (l == 0xffffffff) - l = 0; - raw_sz = sz; - if ((l & PCI_BASE_ADDRESS_SPACE) == - PCI_BASE_ADDRESS_SPACE_MEMORY) { - sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK); - /* - * For 64bit prefetchable memory sz could be 0, if the - * real size is bigger than 4G, so we need to check - * szhi for that. - */ - if (!is_64bit_memory(l) && !sz) - continue; - res->start = l & PCI_BASE_ADDRESS_MEM_MASK; - res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK; + pci_read_config_dword(dev, pos, &l); + pci_write_config_dword(dev, pos, mask); + pci_read_config_dword(dev, pos, &sz); + pci_write_config_dword(dev, pos, l); + + /* + * All bits set in sz means the device isn't working properly. + * If the BAR isn't implemented, all bits must be 0. If it's a + * memory BAR or a ROM, bit 0 must be clear; if it's an io BAR, bit + * 1 must be clear. + */ + if (!sz || sz == 0xffffffff) + goto fail; + + /* + * I don't know how l can have all bits set. Copied from old code. + * Maybe it fixes a bug on some ancient platform. + */ + if (l == 0xffffffff) + l = 0; + + if (type == pci_bar_unknown) { + type = decode_bar(res, l); + res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN; + if (type == pci_bar_io) { + l &= PCI_BASE_ADDRESS_IO_MASK; + mask = PCI_BASE_ADDRESS_IO_MASK & 0xffff; } else { - sz = pci_size(l, sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff); - if (!sz) - continue; - res->start = l & PCI_BASE_ADDRESS_IO_MASK; - res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK; + l &= PCI_BASE_ADDRESS_MEM_MASK; + mask = (u32)PCI_BASE_ADDRESS_MEM_MASK; } - res->end = res->start + (unsigned long) sz; - res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN; - if (is_64bit_memory(l)) { - u32 szhi, lhi; - - pci_read_config_dword(dev, reg+4, &lhi); - pci_write_config_dword(dev, reg+4, ~0); - pci_read_config_dword(dev, reg+4, &szhi); - pci_write_config_dword(dev, reg+4, lhi); - sz64 = ((u64)szhi << 32) | raw_sz; - l64 = ((u64)lhi << 32) | l; - sz64 = pci_size64(l64, sz64, PCI_BASE_ADDRESS_MEM_MASK); - next++; -#if BITS_PER_LONG == 64 - if (!sz64) { - res->start = 0; - res->end = 0; - res->flags = 0; - continue; - } - res->start = l64 & PCI_BASE_ADDRESS_MEM_MASK; - res->end = res->start + sz64; -#else - if (sz64 > 0x100000000ULL) { - dev_err(&dev->dev, "BAR %d: can't handle 64-bit" - " BAR\n", pos); - res->start = 0; - res->flags = 0; - } else if (lhi) { - /* 64-bit wide address, treat as disabled */ - pci_write_config_dword(dev, reg, - l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK); - pci_write_config_dword(dev, reg+4, 0); - res->start = 0; - res->end = sz; - } -#endif + } else { + res->flags |= (l & IORESOURCE_ROM_ENABLE); + l &= PCI_ROM_ADDRESS_MASK; + mask = (u32)PCI_ROM_ADDRESS_MASK; + } + + if (type == pci_bar_mem64) { + u64 l64 = l; + u64 sz64 = sz; + u64 mask64 = mask | (u64)~0 << 32; + + pci_read_config_dword(dev, pos + 4, &l); + pci_write_config_dword(dev, pos + 4, ~0); + pci_read_config_dword(dev, pos + 4, &sz); + pci_write_config_dword(dev, pos + 4, l); + + l64 |= ((u64)l << 32); + sz64 |= ((u64)sz << 32); + + sz64 = pci_size(l64, sz64, mask64); + + if (!sz64) + goto fail; + + if ((BITS_PER_LONG < 64) && (sz64 > 0x100000000ULL)) { + dev_err(&dev->dev, "can't handle 64-bit BAR\n"); + goto fail; + } else if ((BITS_PER_LONG < 64) && l) { + /* Address above 32-bit boundary; disable the BAR */ + pci_write_config_dword(dev, pos, 0); + pci_write_config_dword(dev, pos + 4, 0); + res->start = 0; + res->end = sz64; + } else { + res->start = l64; + res->end = l64 + sz64; } + } else { + sz = pci_size(l, sz, mask); + + if (!sz) + goto fail; + + res->start = l; + res->end = l + sz; } + + out: + return (type == pci_bar_mem64) ? 1 : 0; + fail: + res->flags = 0; + goto out; +} + +static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) +{ + unsigned int pos, reg; + + for (pos = 0; pos < howmany; pos++) { + struct resource *res = &dev->resource[pos]; + reg = PCI_BASE_ADDRESS_0 + (pos << 2); + pos += __pci_read_base(dev, pci_bar_unknown, res, reg); + } + if (rom) { + struct resource *res = &dev->resource[PCI_ROM_RESOURCE]; dev->rom_base_reg = rom; - res = &dev->resource[PCI_ROM_RESOURCE]; - res->name = pci_name(dev); - pci_read_config_dword(dev, rom, &l); - pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE); - pci_read_config_dword(dev, rom, &sz); - pci_write_config_dword(dev, rom, l); - if (l == 0xffffffff) - l = 0; - if (sz && sz != 0xffffffff) { - sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK); - if (sz) { - res->flags = (l & IORESOURCE_ROM_ENABLE) | - IORESOURCE_MEM | IORESOURCE_PREFETCH | - IORESOURCE_READONLY | IORESOURCE_CACHEABLE | - IORESOURCE_SIZEALIGN; - res->start = l & PCI_ROM_ADDRESS_MASK; - res->end = res->start + (unsigned long) sz; - } - } + res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | + IORESOURCE_READONLY | IORESOURCE_CACHEABLE | + IORESOURCE_SIZEALIGN; + __pci_read_base(dev, pci_bar_mem32, res, rom); } } -- cgit v1.2.3 From cc5499c3a607a392e8a7adb934aaf14b2c6a3519 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Mon, 28 Jul 2008 13:39:00 -0400 Subject: PCI: handle 64-bit resources better on 32-bit machines If the kernel is configured to support 64-bit resources on a 32-bit machine, we can support 64-bit BARs properly. Just change the condition to check sizeof(resource_size_t) instead of BITS_PER_LONG. Signed-off-by: Matthew Wilcox Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 3b690c3512f..20363006583 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -270,10 +270,10 @@ static int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, if (!sz64) goto fail; - if ((BITS_PER_LONG < 64) && (sz64 > 0x100000000ULL)) { + if ((sizeof(resource_size_t) < 8) && (sz64 > 0x100000000ULL)) { dev_err(&dev->dev, "can't handle 64-bit BAR\n"); goto fail; - } else if ((BITS_PER_LONG < 64) && l) { + } else if ((sizeof(resource_size_t) < 8) && l) { /* Address above 32-bit boundary; disable the BAR */ pci_write_config_dword(dev, pos, 0); pci_write_config_dword(dev, pos + 4, 0); -- cgit v1.2.3 From 25326277d8d1393d1c66240e6255aca780f9e3eb Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 29 Jul 2008 06:39:26 +0900 Subject: video: Kill off leaked CONFIG_FB_SH7343VOU reference. This came in with the SH-Mobile LCDC changes in commit cfb4f5d1750e05f43902197713c50c29e7dfbc99, kill it off. Reported-by: Robert P. J. Day Signed-off-by: Paul Mundt --- drivers/video/Makefile | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 0ebc1bfd251..a6b55297a7f 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -118,7 +118,6 @@ obj-$(CONFIG_FB_PS3) += ps3fb.o obj-$(CONFIG_FB_SM501) += sm501fb.o obj-$(CONFIG_FB_XILINX) += xilinxfb.o obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o -obj-$(CONFIG_FB_SH7343VOU) += sh7343_voufb.o obj-$(CONFIG_FB_OMAP) += omap/ obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o obj-$(CONFIG_FB_CARMINE) += carminefb.o -- cgit v1.2.3 From ce6fce4295ba727b36fdc73040e444bd1aae64cd Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 25 Jul 2008 15:42:58 -0600 Subject: PCI MSI: Don't disable MSIs if the mask bit isn't supported David Vrabel has a device which generates an interrupt storm on the INTx pin if we disable MSI interrupts altogether. Masking interrupts is only a performance optimisation, so we can ignore the request to mask the interrupt. Signed-off-by: Matthew Wilcox Signed-off-by: Jesse Barnes --- drivers/pci/msi.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 15af618d36e..18354817173 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -126,7 +126,16 @@ static void msix_flush_writes(unsigned int irq) } } -static void msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag) +/* + * PCI 2.3 does not specify mask bits for each MSI interrupt. Attempting to + * mask all MSI interrupts by clearing the MSI enable bit does not work + * reliably as devices without an INTx disable bit will then generate a + * level IRQ which will never be cleared. + * + * Returns 1 if it succeeded in masking the interrupt and 0 if the device + * doesn't support MSI masking. + */ +static int msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag) { struct msi_desc *entry; @@ -144,8 +153,7 @@ static void msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag) mask_bits |= flag & mask; pci_write_config_dword(entry->dev, pos, mask_bits); } else { - __msi_set_enable(entry->dev, entry->msi_attrib.pos, - !flag); + return 0; } break; case PCI_CAP_ID_MSIX: @@ -161,6 +169,7 @@ static void msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag) break; } entry->msi_attrib.masked = !!flag; + return 1; } void read_msi_msg(unsigned int irq, struct msi_msg *msg) -- cgit v1.2.3 From 5fde244d39b88625ac578d83e6625138714de031 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Wed, 23 Jul 2008 10:32:24 +0800 Subject: PCI: disable ASPM per ACPI FADT setting The ACPI FADT table includes an ASPM control bit. If the bit is set, do not enable ASPM since it may indicate that the platform doesn't actually support the feature. Tested-by: Jack Howarth Signed-off-by: Shaohua Li Signed-off-by: Jesse Barnes --- drivers/pci/pci-acpi.c | 7 +++++++ drivers/pci/pcie/aspm.c | 5 +++++ 2 files changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 7764768b6a0..89a2f0fa10f 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -372,6 +373,12 @@ static int __init acpi_pci_init(void) printk(KERN_INFO"ACPI FADT declares the system doesn't support MSI, so disable it\n"); pci_no_msi(); } + + if (acpi_gbl_FADT.boot_flags & BAF_PCIE_ASPM_CONTROL) { + printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n"); + pcie_no_aspm(); + } + ret = register_acpi_bus_type(&acpi_pci_bus); if (ret) return 0; diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index f82495583e6..759c51a4e39 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -808,6 +808,11 @@ static int __init pcie_aspm_disable(char *str) __setup("pcie_noaspm", pcie_aspm_disable); +void pcie_no_aspm(void) +{ + aspm_disabled = 1; +} + #ifdef CONFIG_ACPI #include #include -- cgit v1.2.3 From 149e16372a2066c5474d8a8db9b252afd57eb427 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Wed, 23 Jul 2008 10:32:31 +0800 Subject: PCI: disable ASPM on pre-1.1 PCIe devices Disable ASPM on pre-1.1 PCIe devices, as many of them don't implement it correctly. Tested-by: Jack Howarth Signed-off-by: Shaohua Li Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 13 +++++++++++++ drivers/pci/probe.c | 3 ++- 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 759c51a4e39..704605298c5 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -510,6 +510,7 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) { struct pci_dev *child_dev; int child_pos; + u32 reg32; /* * Some functions in a slot might not all be PCIE functions, very @@ -519,6 +520,18 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); if (!child_pos) return -EINVAL; + + /* + * Disable ASPM for pre-1.1 PCIe device, we follow MS to use + * RBER bit to determine if a function is 1.1 version device + */ + pci_read_config_dword(child_dev, child_pos + PCI_EXP_DEVCAP, + ®32); + if (!(reg32 & PCI_EXP_DEVCAP_RBER)) { + printk("Pre-1.1 PCIe device detected, " + "disable ASPM for %s\n", pci_name(pdev)); + return -EINVAL; + } } return 0; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 20363006583..7098dfb0744 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1057,7 +1057,8 @@ int pci_scan_slot(struct pci_bus *bus, int devfn) } } - if (bus->self) + /* only one slot has pcie device */ + if (bus->self && nr) pcie_aspm_init_link_state(bus->self); return nr; -- cgit v1.2.3 From d6d385743463f38a0da899cd4607e526ad9a049f Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Wed, 23 Jul 2008 10:32:42 +0800 Subject: PCI: add an option to allow ASPM enabled forcibly A new option, pcie_aspm=force, will force ASPM to be enabled, even on system with PCIe 1.0 devices. Signed-off-by: Shaohua Li Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 704605298c5..9a7c9e1408a 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -55,7 +55,7 @@ struct pcie_link_state { struct endpoint_state endpoints[8]; }; -static int aspm_disabled; +static int aspm_disabled, aspm_force; static DEFINE_MUTEX(aspm_lock); static LIST_HEAD(link_list); @@ -527,9 +527,10 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) */ pci_read_config_dword(child_dev, child_pos + PCI_EXP_DEVCAP, ®32); - if (!(reg32 & PCI_EXP_DEVCAP_RBER)) { + if (!(reg32 & PCI_EXP_DEVCAP_RBER && !aspm_force)) { printk("Pre-1.1 PCIe device detected, " - "disable ASPM for %s\n", pci_name(pdev)); + "disable ASPM for %s. It can be enabled forcedly" + " with 'pcie_aspm=force'\n", pci_name(pdev)); return -EINVAL; } } @@ -815,15 +816,22 @@ void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) static int __init pcie_aspm_disable(char *str) { - aspm_disabled = 1; + if (!strcmp(str, "off")) { + aspm_disabled = 1; + printk(KERN_INFO "PCIe ASPM is disabled\n"); + } else if (!strcmp(str, "force")) { + aspm_force = 1; + printk(KERN_INFO "PCIe ASPM is forcedly enabled\n"); + } return 1; } -__setup("pcie_noaspm", pcie_aspm_disable); +__setup("pcie_aspm=", pcie_aspm_disable); void pcie_no_aspm(void) { - aspm_disabled = 1; + if (!aspm_force) + aspm_disabled = 1; } #ifdef CONFIG_ACPI -- cgit v1.2.3 From 362b7077a5546b42131af15ba4776f30c9a72d0c Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 22 Jul 2008 12:37:17 -0600 Subject: PCI: fix bogus "'device' may be used uninitialized" warning in pci_slot I get warnings about 'device' possibly being used uninitialised. While I can deduce this is not true, it seems that GCC can't. This patch changes `check_slot' to return device on success and -1 on error, which shuts GCC up. Acked-by: Alex Chiang Signed-off-by: Matthew Wilcox Signed-off-by: Jesse Barnes --- drivers/acpi/pci_slot.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index dd376f7ad09..d5b4ef89887 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -76,9 +76,9 @@ static struct acpi_pci_driver acpi_pci_slot_driver = { }; static int -check_slot(acpi_handle handle, int *device, unsigned long *sun) +check_slot(acpi_handle handle, unsigned long *sun) { - int retval = 0; + int device = -1; unsigned long adr, sta; acpi_status status; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -89,32 +89,27 @@ check_slot(acpi_handle handle, int *device, unsigned long *sun) if (check_sta_before_sun) { /* If SxFy doesn't have _STA, we just assume it's there */ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); - if (ACPI_SUCCESS(status) && !(sta & ACPI_STA_DEVICE_PRESENT)) { - retval = -1; + if (ACPI_SUCCESS(status) && !(sta & ACPI_STA_DEVICE_PRESENT)) goto out; - } } status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); if (ACPI_FAILURE(status)) { dbg("_ADR returned %d on %s\n", status, (char *)buffer.pointer); - retval = -1; goto out; } - *device = (adr >> 16) & 0xffff; - /* No _SUN == not a slot == bail */ status = acpi_evaluate_integer(handle, "_SUN", NULL, sun); if (ACPI_FAILURE(status)) { dbg("_SUN returned %d on %s\n", status, (char *)buffer.pointer); - retval = -1; goto out; } + device = (adr >> 16) & 0xffff; out: kfree(buffer.pointer); - return retval; + return device; } struct callback_args { @@ -144,7 +139,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) struct callback_args *parent_context = context; struct pci_bus *pci_bus = parent_context->pci_bus; - if (check_slot(handle, &device, &sun)) + device = check_slot(handle, &sun); + if (device < 0) return AE_OK; slot = kmalloc(sizeof(*slot), GFP_KERNEL); -- cgit v1.2.3 From 979b1791e5b8f8b556faeec4c48339e7ed63af9f Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 24 Jul 2008 17:18:38 +0100 Subject: PCI: add D3 power state avoidance quirk Libata has some hacks to deal with certain controllers going silly in D3 state. The right way to handle this is to keep a PCI device flag for such devices. That can then be generalised for no ATA devices with power problems. Signed-off-by: Alan Cox Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 4 ++++ drivers/pci/quirks.c | 13 +++++++++++++ 2 files changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index c95f77d6571..0a3d856833f 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -572,6 +572,10 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state) if (!ret) pci_update_current_state(dev); } + /* This device is quirked not to be put into D3, so + don't put it in D3 */ + if (state == PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3)) + return 0; error = pci_raw_set_power_state(dev, state); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 12d489395fa..0fb36507428 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -923,6 +923,19 @@ static void __init quirk_ide_samemode(struct pci_dev *pdev) } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, quirk_ide_samemode); +/* + * Some ATA devices break if put into D3 + */ + +static void __devinit quirk_no_ata_d3(struct pci_dev *pdev) +{ + /* Quirk the legacy ATA devices only. The AHCI ones are ok */ + if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) + pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3; +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_ANY_ID, quirk_no_ata_d3); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, PCI_ANY_ID, quirk_no_ata_d3); + /* This was originally an Alpha specific thing, but it really fits here. * The i82375 PCI/EISA bridge appears as non-classified. Fix that. */ -- cgit v1.2.3 From 3684a601e4273692b6c80b86e55c728aef675660 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Mon, 28 Jul 2008 17:11:44 -0500 Subject: ipwireless: fix compile failure There's a brown paper bag compile failure introduced by this patch commit a01386924874c4d6d67f8a34e66f04452c2abb69 Author: David Sterba Date: Mon Jul 28 16:53:32 2008 +0200 ipwireless: Preallocate received packet buffers with MRU size Really, it can't ever have been even compile tested. It looks like the closing bracket is in the wrong place, so this is the fix. Signed-off-by: James Bottomley Signed-off-by: Linus Torvalds --- drivers/char/pcmcia/ipwireless/hardware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c index 7d500f82195..4c1820cad71 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.c +++ b/drivers/char/pcmcia/ipwireless/hardware.c @@ -568,7 +568,7 @@ static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw, list_del(&packet->queue); } else { const int min_capacity = - ipwireless_ppp_mru(hw->network + 2); + ipwireless_ppp_mru(hw->network) + 2; int new_capacity; spin_unlock_irqrestore(&hw->lock, flags); -- cgit v1.2.3 From 56edb58be157a06dc147a988af3588059556d392 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Tue, 29 Jul 2008 01:23:32 +0200 Subject: mfd: add platform_data to mfd_cell Adding platform_data to mfd_cell allows passing of platform data directly to the platform_device created for each cell and thus reuse of existing drivers. On the other side it can be used as a hook to mfd_cell itself removing the need in mfd_get_cell method. Signed-off-by: Mike Rapoport Acked-by: Dmitry Baryshkov Signed-off-by: Samuel Ortiz --- drivers/mfd/mfd-core.c | 2 +- drivers/mfd/tc6393xb.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 50207700140..ad4e4d16a36 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -32,7 +32,7 @@ static int mfd_add_device(struct platform_device *parent, pdev->dev.parent = &parent->dev; ret = platform_device_add_data(pdev, - cell, sizeof(struct mfd_cell)); + cell->platform_data, cell->data_size); if (ret) goto fail_device; diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 94e55e8e7ce..9908aaa4881 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -466,6 +466,10 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) tc6393xb_attach_irq(dev); tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data; + tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = + &tc6393xb_cells[TC6393XB_CELL_NAND]; + tc6393xb_cells[TC6393XB_CELL_NAND].data_size = + sizeof(tc6393xb_cells[TC6393XB_CELL_NAND]); retval = mfd_add_devices(dev, tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), -- cgit v1.2.3 From 9a7867e1b34c3575e7e76a05c0c54c6edbdae2a4 Mon Sep 17 00:00:00 2001 From: Luotao Fu Date: Mon, 28 Jul 2008 15:46:32 -0700 Subject: mpc52xx_psc_spi: fix block transfer The block transfer routine in the mpc52xx psc spi driver misinterpret the datasheet. According to the processor datasheet the chipselect is held as long as the EOF is not written. Theoretically blocks of any sizes can be transferred in this way. The old routine however writes an EOF after every word, which has the size of size_of_word. This makes the transfer slow. Also fixed some duplicate code. Signed-off-by: Luotao Fu Signed-off-by: David Brownell Cc: [2.6.25.x, 2.6.26.x] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/spi/mpc52xx_psc_spi.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c index 604e5f0a2d9..25eda71f4bf 100644 --- a/drivers/spi/mpc52xx_psc_spi.c +++ b/drivers/spi/mpc52xx_psc_spi.c @@ -148,7 +148,6 @@ static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi, unsigned rfalarm; unsigned send_at_once = MPC52xx_PSC_BUFSIZE; unsigned recv_at_once; - unsigned bpw = mps->bits_per_word / 8; if (!t->tx_buf && !t->rx_buf && t->len) return -EINVAL; @@ -164,22 +163,15 @@ static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi, } dev_dbg(&spi->dev, "send %d bytes...\n", send_at_once); - if (tx_buf) { - for (; send_at_once; sb++, send_at_once--) { - /* set EOF flag */ - if (mps->bits_per_word - && (sb + 1) % bpw == 0) - out_8(&psc->ircr2, 0x01); + for (; send_at_once; sb++, send_at_once--) { + /* set EOF flag before the last word is sent */ + if (send_at_once == 1) + out_8(&psc->ircr2, 0x01); + + if (tx_buf) out_8(&psc->mpc52xx_psc_buffer_8, tx_buf[sb]); - } - } else { - for (; send_at_once; sb++, send_at_once--) { - /* set EOF flag */ - if (mps->bits_per_word - && ((sb + 1) % bpw) == 0) - out_8(&psc->ircr2, 0x01); + else out_8(&psc->mpc52xx_psc_buffer_8, 0); - } } -- cgit v1.2.3 From cb1d0a7a5d2e537f2f6ada22883abee1762e94b2 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 28 Jul 2008 15:46:33 -0700 Subject: spi_s3c24xx: really assign busnum The original "Pass the bus number we expect the S3C24XX SPI driver to attach to via the platform data." [1] patch was mis-sent, and missed two important parts of the diff, which was to actually set the bus_num field and add the relevant field to the platform data. The previous commit 50f426b55d919dd017af35bb6a08753d1f262920 promised to add a bus_num field, but failed to include the two hunks that added this field to include/asm-arm/arch-s3c2410/spi.h and then pass it to the spi core when creating the new master field in drivers/spi/spi_s3c24xx.c. [1] git commit 50f426b55d919dd017af35bb6a08753d1f262920 Signed-off-by: Ben Dooks Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/spi/spi_s3c24xx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c index 0885cc357a3..1c643c9e1f1 100644 --- a/drivers/spi/spi_s3c24xx.c +++ b/drivers/spi/spi_s3c24xx.c @@ -270,6 +270,7 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev) /* setup the master state. */ master->num_chipselect = hw->pdata->num_cs; + master->bus_num = pdata->bus_num; /* setup the state for the bitbang driver */ -- cgit v1.2.3 From c27ef92d8e0c29a9e8b8ee1b04f3d2cace482d92 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Mon, 28 Jul 2008 15:46:39 -0700 Subject: sh7760fb: write colormap value to hardware The computed color value is never actually written to hardware colormap register. Signed-off-by: Manuel Lauss Cc: Nobuhiro Iwamatsu Cc: Munakata Hisao Cc: Paul Mundt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/sh7760fb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/video/sh7760fb.c b/drivers/video/sh7760fb.c index 4d0e28c5790..8d0212da451 100644 --- a/drivers/video/sh7760fb.c +++ b/drivers/video/sh7760fb.c @@ -152,6 +152,7 @@ static int sh7760fb_setcmap(struct fb_cmap *cmap, struct fb_info *info) col |= ((*g) & 0xff) << 8; col |= ((*b) & 0xff); col &= SH7760FB_PALETTE_MASK; + iowrite32(col, par->base + LDPR(s)); if (s < 16) ((u32 *) (info->pseudo_palette))[s] = s; -- cgit v1.2.3 From 424f525a1241351da947fb48a938128ddd774511 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 29 Jul 2008 01:30:26 +0200 Subject: mfd: accept pure device as a parent, not only platform_device Signed-off-by: Dmitry Baryshkov Signed-off-by: Samuel Ortiz --- drivers/mfd/mfd-core.c | 14 +++++++------- drivers/mfd/tc6393xb.c | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index ad4e4d16a36..9c9c126ed33 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -15,7 +15,7 @@ #include #include -static int mfd_add_device(struct platform_device *parent, +static int mfd_add_device(struct device *parent, int id, const struct mfd_cell *cell, struct resource *mem_base, int irq_base) @@ -25,11 +25,11 @@ static int mfd_add_device(struct platform_device *parent, int ret = -ENOMEM; int r; - pdev = platform_device_alloc(cell->name, parent->id); + pdev = platform_device_alloc(cell->name, id); if (!pdev) goto fail_alloc; - pdev->dev.parent = &parent->dev; + pdev->dev.parent = parent; ret = platform_device_add_data(pdev, cell->platform_data, cell->data_size); @@ -75,7 +75,7 @@ fail_alloc: return ret; } -int mfd_add_devices(struct platform_device *parent, +int mfd_add_devices(struct device *parent, int id, const struct mfd_cell *cells, int n_devs, struct resource *mem_base, int irq_base) @@ -84,7 +84,7 @@ int mfd_add_devices(struct platform_device *parent, int ret = 0; for (i = 0; i < n_devs; i++) { - ret = mfd_add_device(parent, cells + i, mem_base, irq_base); + ret = mfd_add_device(parent, id, cells + i, mem_base, irq_base); if (ret) break; } @@ -102,9 +102,9 @@ static int mfd_remove_devices_fn(struct device *dev, void *unused) return 0; } -void mfd_remove_devices(struct platform_device *parent) +void mfd_remove_devices(struct device *parent) { - device_for_each_child(&parent->dev, NULL, mfd_remove_devices_fn); + device_for_each_child(parent, NULL, mfd_remove_devices_fn); } EXPORT_SYMBOL(mfd_remove_devices); diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 9908aaa4881..f4fd797c159 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -471,7 +471,7 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) tc6393xb_cells[TC6393XB_CELL_NAND].data_size = sizeof(tc6393xb_cells[TC6393XB_CELL_NAND]); - retval = mfd_add_devices(dev, + retval = mfd_add_devices(&dev->dev, dev->id, tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), iomem, tcpd->irq_base); @@ -505,7 +505,7 @@ static int __devexit tc6393xb_remove(struct platform_device *dev) struct tc6393xb *tc6393xb = platform_get_drvdata(dev); int ret; - mfd_remove_devices(dev); + mfd_remove_devices(&dev->dev); if (tc6393xb->irq) tc6393xb_detach_irq(dev); -- cgit v1.2.3 From 0c12091d82e48dc423fb1f51eb0062c557a084af Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 29 Jul 2008 09:58:31 -0500 Subject: lguest: Guest int3 fix Ron Minnich noticed that guest userspace gets a GPF when it tries to int3: we need to copy the privilege level from the guest-supplied IDT to the real IDT. int3 is the only common case where guest userspace expects to invoke an interrupt, so that's the symptom of failing to do this. Signed-off-by: Rusty Russell --- drivers/lguest/interrupts_and_traps.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c index 0414ddf8758..a1039068f95 100644 --- a/drivers/lguest/interrupts_and_traps.c +++ b/drivers/lguest/interrupts_and_traps.c @@ -406,7 +406,8 @@ void load_guest_idt_entry(struct lg_cpu *cpu, unsigned int num, u32 lo, u32 hi) * deliver_trap() to bounce it back into the Guest. */ static void default_idt_entry(struct desc_struct *idt, int trap, - const unsigned long handler) + const unsigned long handler, + const struct desc_struct *base) { /* A present interrupt gate. */ u32 flags = 0x8e00; @@ -415,6 +416,10 @@ static void default_idt_entry(struct desc_struct *idt, * the Guest to use the "int" instruction to trigger it. */ if (trap == LGUEST_TRAP_ENTRY) flags |= (GUEST_PL << 13); + else if (base) + /* Copy priv. level from what Guest asked for. This allows + * debug (int 3) traps from Guest userspace, for example. */ + flags |= (base->b & 0x6000); /* Now pack it into the IDT entry in its weird format. */ idt->a = (LGUEST_CS<<16) | (handler&0x0000FFFF); @@ -428,7 +433,7 @@ void setup_default_idt_entries(struct lguest_ro_state *state, unsigned int i; for (i = 0; i < ARRAY_SIZE(state->guest_idt); i++) - default_idt_entry(&state->guest_idt[i], i, def[i]); + default_idt_entry(&state->guest_idt[i], i, def[i], NULL); } /*H:240 We don't use the IDT entries in the "struct lguest" directly, instead @@ -442,6 +447,8 @@ void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt, /* We can simply copy the direct traps, otherwise we use the default * ones in the Switcher: they will return to the Host. */ for (i = 0; i < ARRAY_SIZE(cpu->arch.idt); i++) { + const struct desc_struct *gidt = &cpu->arch.idt[i]; + /* If no Guest can ever override this trap, leave it alone. */ if (!direct_trap(i)) continue; @@ -449,12 +456,15 @@ void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt, /* Only trap gates (type 15) can go direct to the Guest. * Interrupt gates (type 14) disable interrupts as they are * entered, which we never let the Guest do. Not present - * entries (type 0x0) also can't go direct, of course. */ - if (idt_type(cpu->arch.idt[i].a, cpu->arch.idt[i].b) == 0xF) - idt[i] = cpu->arch.idt[i]; + * entries (type 0x0) also can't go direct, of course. + * + * If it can't go direct, we still need to copy the priv. level: + * they might want to give userspace access to a software + * interrupt. */ + if (idt_type(gidt->a, gidt->b) == 0xF) + idt[i] = *gidt; else - /* Reset it to the default. */ - default_idt_entry(&idt[i], i, def[i]); + default_idt_entry(&idt[i], i, def[i], gidt); } } -- cgit v1.2.3 From 0a707210aa1b8ac40fe781b2a9d0b203b6ebb921 Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Tue, 8 Jul 2008 10:29:42 +0200 Subject: lguest: fix switcher_page leak on unload map_switcher allocates the array, unmap_switcher has to free it accordingly. Signed-off-by: Johannes Weiner Signed-off-by: Rusty Russell --- drivers/lguest/core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c index 5eea4356d70..90663e01a56 100644 --- a/drivers/lguest/core.c +++ b/drivers/lguest/core.c @@ -135,6 +135,7 @@ static void unmap_switcher(void) /* Now we just need to free the pages we copied the switcher into */ for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) __free_pages(switcher_page[i], 0); + kfree(switcher_page); } /*H:032 -- cgit v1.2.3 From cf485e566bc4a8098680162e1cc2ac1dfbef8a3c Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 9 Jun 2008 16:22:48 -0700 Subject: lguest: use cpu capability accessors To support my little make-x86-bitops-use-proper-typechecking projectlet. Cc: Thomas Gleixner Cc: Andrea Arcangeli Signed-off-by: Andrew Morton Acked-by: Ingo Molnar Signed-off-by: Rusty Russell --- drivers/lguest/x86/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c index 95dfda52b4f..bf7942327bd 100644 --- a/drivers/lguest/x86/core.c +++ b/drivers/lguest/x86/core.c @@ -480,7 +480,7 @@ void __init lguest_arch_host_init(void) * bit on its CPU, depending on the argument (0 == unset). */ on_each_cpu(adjust_pge, (void *)0, 1); /* Turn off the feature in the global feature set. */ - clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability); + clear_cpu_cap(&boot_cpu_data, X86_FEATURE_PGE); } put_online_cpus(); }; @@ -491,7 +491,7 @@ void __exit lguest_arch_host_fini(void) /* If we had PGE before we started, turn it back on now. */ get_online_cpus(); if (cpu_had_pge) { - set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability); + set_cpu_cap(&boot_cpu_data, X86_FEATURE_PGE); /* adjust_pge's argument "1" means set PGE. */ on_each_cpu(adjust_pge, (void *)1, 1); } -- cgit v1.2.3 From df10cfbc4d7ab93260d997df754219d390d62a9d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 28 Jul 2008 23:10:39 -0700 Subject: md: do not progress the resync process if the stripe was blocked handle_stripe will take no action on a stripe when waiting for userspace to unblock the array, so do not report completed sectors. Signed-off-by: Dan Williams --- drivers/md/raid5.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 46132fca346..b428e15d59a 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2507,7 +2507,7 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh, * */ -static void handle_stripe5(struct stripe_head *sh) +static bool handle_stripe5(struct stripe_head *sh) { raid5_conf_t *conf = sh->raid_conf; int disks = sh->disks, i; @@ -2755,9 +2755,11 @@ static void handle_stripe5(struct stripe_head *sh) ops_run_io(sh, &s); return_io(return_bi); + + return blocked_rdev == NULL; } -static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) +static bool handle_stripe6(struct stripe_head *sh, struct page *tmp_page) { raid6_conf_t *conf = sh->raid_conf; int disks = sh->disks; @@ -2968,14 +2970,17 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) ops_run_io(sh, &s); return_io(return_bi); + + return blocked_rdev == NULL; } -static void handle_stripe(struct stripe_head *sh, struct page *tmp_page) +/* returns true if the stripe was handled */ +static bool handle_stripe(struct stripe_head *sh, struct page *tmp_page) { if (sh->raid_conf->level == 6) - handle_stripe6(sh, tmp_page); + return handle_stripe6(sh, tmp_page); else - handle_stripe5(sh); + return handle_stripe5(sh); } @@ -3691,7 +3696,9 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski clear_bit(STRIPE_INSYNC, &sh->state); spin_unlock(&sh->lock); - handle_stripe(sh, NULL); + /* wait for any blocked device to be handled */ + while(unlikely(!handle_stripe(sh, NULL))) + ; release_stripe(sh); return STRIPE_SECTORS; -- cgit v1.2.3 From e542713529e323ff09d7aeb5806cf29f6f160f53 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 28 Jul 2008 23:28:06 -0700 Subject: md: do not count blocked devices as spares remove_and_add_spares() assumes that failed devices have been hot-removed from the array. Removal is skipped in the 'blocked' case so do not count a device in this state as 'spare'. Signed-off-by: Dan Williams --- drivers/md/md.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index 0f1b8309642..c7aae66c6f9 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5996,7 +5996,8 @@ static int remove_and_add_spares(mddev_t *mddev) if (mddev->degraded) { rdev_for_each(rdev, rtmp, mddev) { if (rdev->raid_disk >= 0 && - !test_bit(In_sync, &rdev->flags)) + !test_bit(In_sync, &rdev->flags) && + !test_bit(Blocked, &rdev->flags)) spares++; if (rdev->raid_disk < 0 && !test_bit(Faulty, &rdev->flags)) { -- cgit v1.2.3 From 0764bff445bb13cd17e41b6ab196ef83c23c6c17 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 29 Jul 2008 22:10:01 +0900 Subject: sh: More header path fixups for mach dir refactoring. Signed-off-by: Paul Mundt --- drivers/cdrom/gdrom.c | 4 ++-- drivers/input/keyboard/maple_keyb.c | 1 - drivers/video/pvr2fb.c | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index 71ec426ecff..1e0455bd6df 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -39,8 +39,8 @@ #include #include #include -#include -#include +#include +#include #define GDROM_DEV_NAME "gdrom" #define GD_SESSION_OFFSET 150 diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c index 2b404284c28..7797ef6e5e6 100644 --- a/drivers/input/keyboard/maple_keyb.c +++ b/drivers/input/keyboard/maple_keyb.c @@ -27,7 +27,6 @@ #include #include #include -#include /* Very simple mutex to ensure proper cleanup */ static DEFINE_MUTEX(maple_keyb_mutex); diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c index 8c863a7f654..0a0fd48a856 100644 --- a/drivers/video/pvr2fb.c +++ b/drivers/video/pvr2fb.c @@ -58,18 +58,18 @@ #ifdef CONFIG_SH_DREAMCAST #include -#include +#include #endif #ifdef CONFIG_SH_DMA #include -#include +#include #include #endif #ifdef CONFIG_SH_STORE_QUEUES #include -#include +#include #endif #ifndef PCI_DEVICE_ID_NEC_NEON250 -- cgit v1.2.3 From 1795cf48b322b4d19230a40dbe7181acedd34a94 Mon Sep 17 00:00:00 2001 From: Adrian McMenamin Date: Tue, 29 Jul 2008 22:10:56 +0900 Subject: sh/maple: clean maple bus code This patch cleans up the handling of the maple bus queue to remove the risk of races when adding packets. It also removes references to the redundant connect and disconnect functions. Signed-off-by: Adrian McMenamin Signed-off-by: Paul Mundt --- drivers/sh/maple/maple.c | 265 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 184 insertions(+), 81 deletions(-) (limited to 'drivers') diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c index 617efb1640b..be97789fa5f 100644 --- a/drivers/sh/maple/maple.c +++ b/drivers/sh/maple/maple.c @@ -24,13 +24,12 @@ #include #include #include +#include #include #include #include -#include -#include -#include -#include +#include +#include MODULE_AUTHOR("Yaegshi Takeshi, Paul Mundt, M.R. Brown, Adrian McMenamin"); MODULE_DESCRIPTION("Maple bus driver for Dreamcast"); @@ -46,14 +45,15 @@ static DECLARE_WORK(maple_vblank_process, maple_vblank_handler); static LIST_HEAD(maple_waitq); static LIST_HEAD(maple_sentq); -static DEFINE_MUTEX(maple_list_lock); +/* mutex to protect queue of waiting packets */ +static DEFINE_MUTEX(maple_wlist_lock); static struct maple_driver maple_dummy_driver; static struct device maple_bus; static int subdevice_map[MAPLE_PORTS]; static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr; static unsigned long maple_pnp_time; -static int started, scanning, liststatus, fullscan; +static int started, scanning, fullscan; static struct kmem_cache *maple_queue_cache; struct maple_device_specify { @@ -129,35 +129,124 @@ static void maple_release_device(struct device *dev) kfree(mdev); } -/** +/* * maple_add_packet - add a single instruction to the queue - * @mq: instruction to add to waiting queue + * @mdev - maple device + * @function - function on device being queried + * @command - maple command to add + * @length - length of command string (in 32 bit words) + * @data - remainder of command string */ -void maple_add_packet(struct mapleq *mq) +int maple_add_packet(struct maple_device *mdev, u32 function, u32 command, + size_t length, void *data) { - mutex_lock(&maple_list_lock); - list_add(&mq->list, &maple_waitq); - mutex_unlock(&maple_list_lock); + int locking, ret = 0; + void *sendbuf = NULL; + + mutex_lock(&maple_wlist_lock); + /* bounce if device already locked */ + locking = mutex_is_locked(&mdev->mq->mutex); + if (locking) { + ret = -EBUSY; + goto out; + } + + mutex_lock(&mdev->mq->mutex); + + if (length) { + sendbuf = kmalloc(length * 4, GFP_KERNEL); + if (!sendbuf) { + mutex_unlock(&mdev->mq->mutex); + ret = -ENOMEM; + goto out; + } + ((__be32 *)sendbuf)[0] = cpu_to_be32(function); + } + + mdev->mq->command = command; + mdev->mq->length = length; + if (length > 1) + memcpy(sendbuf + 4, data, (length - 1) * 4); + mdev->mq->sendbuf = sendbuf; + + list_add(&mdev->mq->list, &maple_waitq); +out: + mutex_unlock(&maple_wlist_lock); + return ret; } EXPORT_SYMBOL_GPL(maple_add_packet); +/* + * maple_add_packet_sleeps - add a single instruction to the queue + * - waits for lock to be free + * @mdev - maple device + * @function - function on device being queried + * @command - maple command to add + * @length - length of command string (in 32 bit words) + * @data - remainder of command string + */ +int maple_add_packet_sleeps(struct maple_device *mdev, u32 function, + u32 command, size_t length, void *data) +{ + int locking, ret = 0; + void *sendbuf = NULL; + + locking = mutex_lock_interruptible(&mdev->mq->mutex); + if (locking) { + ret = -EIO; + goto out; + } + + if (length) { + sendbuf = kmalloc(length * 4, GFP_KERNEL); + if (!sendbuf) { + mutex_unlock(&mdev->mq->mutex); + ret = -ENOMEM; + goto out; + } + ((__be32 *)sendbuf)[0] = cpu_to_be32(function); + } + + mdev->mq->command = command; + mdev->mq->length = length; + if (length > 1) + memcpy(sendbuf + 4, data, (length - 1) * 4); + mdev->mq->sendbuf = sendbuf; + + mutex_lock(&maple_wlist_lock); + list_add(&mdev->mq->list, &maple_waitq); + mutex_unlock(&maple_wlist_lock); +out: + return ret; +} +EXPORT_SYMBOL_GPL(maple_add_packet_sleeps); + static struct mapleq *maple_allocq(struct maple_device *mdev) { struct mapleq *mq; mq = kmalloc(sizeof(*mq), GFP_KERNEL); if (!mq) - return NULL; + goto failed_nomem; mq->dev = mdev; mq->recvbufdcsp = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL); mq->recvbuf = (void *) P2SEGADDR(mq->recvbufdcsp); - if (!mq->recvbuf) { - kfree(mq); - return NULL; - } + if (!mq->recvbuf) + goto failed_p2; + /* + * most devices do not need the mutex - but + * anything that injects block reads or writes + * will rely on it + */ + mutex_init(&mq->mutex); return mq; + +failed_p2: + kfree(mq); +failed_nomem: + return NULL; } static struct maple_device *maple_alloc_dev(int port, int unit) @@ -178,7 +267,6 @@ static struct maple_device *maple_alloc_dev(int port, int unit) } mdev->dev.bus = &maple_bus_type; mdev->dev.parent = &maple_bus; - mdev->function = 0; return mdev; } @@ -216,7 +304,6 @@ static void maple_build_block(struct mapleq *mq) *maple_sendptr++ = PHYSADDR(mq->recvbuf); *maple_sendptr++ = mq->command | (to << 8) | (from << 16) | (len << 24); - while (len-- > 0) *maple_sendptr++ = *lsendbuf++; } @@ -224,22 +311,27 @@ static void maple_build_block(struct mapleq *mq) /* build up command queue */ static void maple_send(void) { - int i; - int maple_packets; + int i, maple_packets = 0; struct mapleq *mq, *nmq; if (!list_empty(&maple_sentq)) return; - if (list_empty(&maple_waitq) || !maple_dma_done()) + mutex_lock(&maple_wlist_lock); + if (list_empty(&maple_waitq) || !maple_dma_done()) { + mutex_unlock(&maple_wlist_lock); return; - maple_packets = 0; - maple_sendptr = maple_lastptr = maple_sendbuf; + } + mutex_unlock(&maple_wlist_lock); + maple_lastptr = maple_sendbuf; + maple_sendptr = maple_sendbuf; + mutex_lock(&maple_wlist_lock); list_for_each_entry_safe(mq, nmq, &maple_waitq, list) { maple_build_block(mq); list_move(&mq->list, &maple_sentq); if (maple_packets++ > MAPLE_MAXPACKETS) break; } + mutex_unlock(&maple_wlist_lock); if (maple_packets > 0) { for (i = 0; i < (1 << MAPLE_DMA_PAGES); i++) dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE, @@ -247,7 +339,8 @@ static void maple_send(void) } } -static int attach_matching_maple_driver(struct device_driver *driver, +/* check if there is a driver registered likely to match this device */ +static int check_matching_maple_driver(struct device_driver *driver, void *devptr) { struct maple_driver *maple_drv; @@ -255,12 +348,8 @@ static int attach_matching_maple_driver(struct device_driver *driver, mdev = devptr; maple_drv = to_maple_driver(driver); - if (mdev->devinfo.function & be32_to_cpu(maple_drv->function)) { - if (maple_drv->connect(mdev) == 0) { - mdev->driver = maple_drv; - return 1; - } - } + if (mdev->devinfo.function & cpu_to_be32(maple_drv->function)) + return 1; return 0; } @@ -268,11 +357,6 @@ static void maple_detach_driver(struct maple_device *mdev) { if (!mdev) return; - if (mdev->driver) { - if (mdev->driver->disconnect) - mdev->driver->disconnect(mdev); - } - mdev->driver = NULL; device_unregister(&mdev->dev); mdev = NULL; } @@ -328,8 +412,8 @@ static void maple_attach_driver(struct maple_device *mdev) mdev->port, mdev->unit, function); matched = - bus_for_each_drv(&maple_bus_type, NULL, mdev, - attach_matching_maple_driver); + bus_for_each_drv(&maple_bus_type, NULL, mdev, + check_matching_maple_driver); if (matched == 0) { /* Driver does not exist yet */ @@ -373,45 +457,48 @@ static int detach_maple_device(struct device *device, void *portptr) static int setup_maple_commands(struct device *device, void *ignored) { + int add; struct maple_device *maple_dev = to_maple_dev(device); if ((maple_dev->interval > 0) && time_after(jiffies, maple_dev->when)) { - maple_dev->when = jiffies + maple_dev->interval; - maple_dev->mq->command = MAPLE_COMMAND_GETCOND; - maple_dev->mq->sendbuf = &maple_dev->function; - maple_dev->mq->length = 1; - maple_add_packet(maple_dev->mq); - liststatus++; + /* bounce if we cannot lock */ + add = maple_add_packet(maple_dev, + be32_to_cpu(maple_dev->devinfo.function), + MAPLE_COMMAND_GETCOND, 1, NULL); + if (!add) + maple_dev->when = jiffies + maple_dev->interval; } else { - if (time_after(jiffies, maple_pnp_time)) { - maple_dev->mq->command = MAPLE_COMMAND_DEVINFO; - maple_dev->mq->length = 0; - maple_add_packet(maple_dev->mq); - liststatus++; - } + if (time_after(jiffies, maple_pnp_time)) + /* This will also bounce */ + maple_add_packet(maple_dev, 0, + MAPLE_COMMAND_DEVINFO, 0, NULL); } - return 0; } /* VBLANK bottom half - implemented via workqueue */ static void maple_vblank_handler(struct work_struct *work) { - if (!maple_dma_done()) - return; - if (!list_empty(&maple_sentq)) + if (!list_empty(&maple_sentq) || !maple_dma_done()) return; + ctrl_outl(0, MAPLE_ENABLE); - liststatus = 0; + bus_for_each_dev(&maple_bus_type, NULL, NULL, setup_maple_commands); + if (time_after(jiffies, maple_pnp_time)) maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL; - if (liststatus && list_empty(&maple_sentq)) { - INIT_LIST_HEAD(&maple_sentq); + + mutex_lock(&maple_wlist_lock); + if (!list_empty(&maple_waitq) && list_empty(&maple_sentq)) { + mutex_unlock(&maple_wlist_lock); maple_send(); + } else { + mutex_unlock(&maple_wlist_lock); } + maplebus_dma_reset(); } @@ -422,8 +509,8 @@ static void maple_map_subunits(struct maple_device *mdev, int submask) struct maple_device *mdev_add; struct maple_device_specify ds; + ds.port = mdev->port; for (k = 0; k < 5; k++) { - ds.port = mdev->port; ds.unit = k + 1; retval = bus_for_each_dev(&maple_bus_type, NULL, &ds, @@ -437,9 +524,9 @@ static void maple_map_subunits(struct maple_device *mdev, int submask) mdev_add = maple_alloc_dev(mdev->port, k + 1); if (!mdev_add) return; - mdev_add->mq->command = MAPLE_COMMAND_DEVINFO; - mdev_add->mq->length = 0; - maple_add_packet(mdev_add->mq); + maple_add_packet(mdev_add, 0, MAPLE_COMMAND_DEVINFO, + 0, NULL); + /* mark that we are checking sub devices */ scanning = 1; } submask = submask >> 1; @@ -505,6 +592,28 @@ static void maple_response_devinfo(struct maple_device *mdev, } } +static void maple_port_rescan(void) +{ + int i; + struct maple_device *mdev; + + fullscan = 1; + for (i = 0; i < MAPLE_PORTS; i++) { + if (checked[i] == false) { + fullscan = 0; + mdev = baseunits[i]; + /* + * test lock in case scan has failed + * but device is still locked + */ + if (mutex_is_locked(&mdev->mq->mutex)) + mutex_unlock(&mdev->mq->mutex); + maple_add_packet(mdev, 0, MAPLE_COMMAND_DEVINFO, + 0, NULL); + } + } +} + /* maple dma end bottom half - implemented via workqueue */ static void maple_dma_handler(struct work_struct *work) { @@ -512,7 +621,6 @@ static void maple_dma_handler(struct work_struct *work) struct maple_device *dev; char *recvbuf; enum maple_code code; - int i; if (!maple_dma_done()) return; @@ -522,6 +630,10 @@ static void maple_dma_handler(struct work_struct *work) recvbuf = mq->recvbuf; code = recvbuf[0]; dev = mq->dev; + kfree(mq->sendbuf); + mutex_unlock(&mq->mutex); + list_del_init(&mq->list); + switch (code) { case MAPLE_RESPONSE_NONE: maple_response_none(dev, mq); @@ -558,26 +670,16 @@ static void maple_dma_handler(struct work_struct *work) break; } } - INIT_LIST_HEAD(&maple_sentq); + /* if scanning is 1 then we have subdevices to check */ if (scanning == 1) { maple_send(); scanning = 2; } else scanning = 0; - - if (!fullscan) { - fullscan = 1; - for (i = 0; i < MAPLE_PORTS; i++) { - if (checked[i] == false) { - fullscan = 0; - dev = baseunits[i]; - dev->mq->command = - MAPLE_COMMAND_DEVINFO; - dev->mq->length = 0; - maple_add_packet(dev->mq); - } - } - } + /*check if we have actually tested all ports yet */ + if (!fullscan) + maple_port_rescan(); + /* mark that we have been through the first scan */ if (started == 0) started = 1; } @@ -631,7 +733,7 @@ static int match_maple_bus_driver(struct device *devptr, if (maple_dev->devinfo.function == 0xFFFFFFFF) return 0; else if (maple_dev->devinfo.function & - be32_to_cpu(maple_drv->function)) + cpu_to_be32(maple_drv->function)) return 1; return 0; } @@ -713,6 +815,9 @@ static int __init maple_bus_init(void) if (!maple_queue_cache) goto cleanup_bothirqs; + INIT_LIST_HEAD(&maple_waitq); + INIT_LIST_HEAD(&maple_sentq); + /* setup maple ports */ for (i = 0; i < MAPLE_PORTS; i++) { checked[i] = false; @@ -723,9 +828,7 @@ static int __init maple_bus_init(void) maple_free_dev(mdev[i]); goto cleanup_cache; } - mdev[i]->mq->command = MAPLE_COMMAND_DEVINFO; - mdev[i]->mq->length = 0; - maple_add_packet(mdev[i]->mq); + maple_add_packet(mdev[i], 0, MAPLE_COMMAND_DEVINFO, 0, NULL); subdevice_map[i] = 0; } -- cgit v1.2.3 From c2697968c012cfdba2d92fa6e27e3e34f918af2f Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 30 Jul 2008 00:56:39 +0900 Subject: serial: sh-sci: Fix up SH7760/SH7780/SH7785 early printk regression. As noted by Manuel: Commit c63847a3621d2bac054f5709783860ecabd0ee7e ("sh: Add SCIF2 support for SH7763.") broke build with CONFIG_EARLY_PRINTK enabled for me (SH7760): CC arch/sh/kernel/early_printk.o /mnt/work/sh7760/kernel/linux-2.6.git/arch/sh/kernel/early_printk.c: In function 'scif_sercon_putc': /mnt/work/sh7760/kernel/linux-2.6.git/arch/sh/kernel/early_printk.c:84: error: implicit declaration of function 'sci_SCFDR_in' Move the SH7763 definitions out on their own, so they don't create additional confusion within the SH7760/SH7780/SH7785 block. Restore the deleted SCFDR definition for these parts. Reported-by: Manuel Lauss Signed-off-by: Paul Mundt --- drivers/serial/sh-sci.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index cd728df6a01..8a0749e34ca 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -451,19 +451,21 @@ SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16, 0x04, 8) SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8, 0x05, 8) SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16) #if defined(CONFIG_CPU_SUBTYPE_SH7760) || \ - defined(CONFIG_CPU_SUBTYPE_SH7763) || \ defined(CONFIG_CPU_SUBTYPE_SH7780) || \ defined(CONFIG_CPU_SUBTYPE_SH7785) +SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16) SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16) SCIF_FNS(SCSPTR, 0, 0, 0x24, 16) SCIF_FNS(SCLSR, 0, 0, 0x28, 16) -#if defined(CONFIG_CPU_SUBTYPE_SH7763) -/* SH7763 SCIF2 */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7763) SCIF_FNS(SCFDR, 0, 0, 0x1C, 16) SCIF_FNS(SCSPTR2, 0, 0, 0x20, 16) -SCIF_FNS(SCLSR2, 0, 0, 0x24, 16) -#endif /* CONFIG_CPU_SUBTYPE_SH7763 */ +SCIF_FNS(SCLSR2, 0, 0, 0x24, 16) +SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16) +SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16) +SCIF_FNS(SCSPTR, 0, 0, 0x24, 16) +SCIF_FNS(SCLSR, 0, 0, 0x28, 16) #else SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) #if defined(CONFIG_CPU_SUBTYPE_SH7722) -- cgit v1.2.3 From 193f3c2f1531ec9755a87a33038fba3ee29f6ca5 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 30 Jul 2008 02:16:12 +0900 Subject: video: Fix up hp6xx driver build regressions. This is some more fallout from the header reorganization, fix up the paths accordingly. Signed-off-by: Paul Mundt --- drivers/video/backlight/hp680_bl.c | 2 +- drivers/video/hitfb.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index fbea2bd129c..6fa0b9d5559 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c index 392a8be6aa7..e6467cf9f19 100644 --- a/drivers/video/hitfb.c +++ b/drivers/video/hitfb.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #define WIDTH 640 -- cgit v1.2.3 From 605a0bd66d9d55e9ba46da1a9e5140c68bdf6d85 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 15 Jul 2008 10:10:01 +0200 Subject: mac80211: remove IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE flag I forgot this in the previous patch that made it unused. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 3 +-- drivers/net/wireless/b43legacy/main.c | 3 +-- drivers/net/wireless/iwlwifi/iwl-core.c | 3 +-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 3 +-- drivers/net/wireless/rt2x00/rt2500usb.c | 1 - drivers/net/wireless/rt2x00/rt61pci.c | 1 - drivers/net/wireless/rt2x00/rt73usb.c | 1 - drivers/net/wireless/zd1211rw/zd_mac.c | 1 - 8 files changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index e78319aa47c..3bf3a869361 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4645,8 +4645,7 @@ static int b43_wireless_init(struct ssb_device *dev) } /* fill hw info */ - hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_RX_INCLUDES_FCS | + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index a1b8bf3ee73..cb5ad4f7fb2 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3702,8 +3702,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev) } /* fill hw info */ - hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_RX_INCLUDES_FCS | + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; hw->queues = 1; /* FIXME: hardware has more queues */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index a44188bf445..e3427c205cc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -818,8 +818,7 @@ int iwl_setup_mac(struct iwl_priv *priv) hw->rate_control_algorithm = "iwl-4965-rs"; /* Tell mac80211 our characteristics */ - hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_SIGNAL_DBM | + hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 4a22d3fba75..05121f395c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -7899,8 +7899,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->ibss_beacon = NULL; /* Tell mac80211 our characteristics */ - hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_SIGNAL_DBM | + hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; /* 4 EDCA QOS priorities */ diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 3558cb21074..449c8d39348 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1650,7 +1650,6 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) * Initialize all hw fields. */ rt2x00dev->hw->flags = - IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index f7c1f92c144..ec4ec65d94f 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2278,7 +2278,6 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) * Initialize all hw fields. */ rt2x00dev->hw->flags = - IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = 0; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index d383735ab8f..b9efa7f76c9 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1871,7 +1871,6 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) * Initialize all hw fields. */ rt2x00dev->hw->flags = - IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index fcc532bb6a7..4d7b98b0503 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -935,7 +935,6 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band; hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | IEEE80211_HW_SIGNAL_DB; hw->max_signal = 100; -- cgit v1.2.3 From 3a0f2c871849f23c1070965bf94dec3f9c0b479d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 15 Jul 2008 17:44:18 +0200 Subject: Ath5k: fix memory corruption MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When signal is noisy, hardware can use all RX buffers and since the last entry in the list is self-linked, it overwrites the entry until we link new buffers. Ensure that we don't free this last one until we are 100% sure that it is not used by the hardware anymore to not cause memory curruption as can be seen below. This is done by checking next buffer in the list. Even after that we know that the hardware refetched the new link and proceeded further (the next buffer is ready) we can finally free the overwritten buffer. We discard it since the status in its descriptor is overwritten (OR-ed by new status) too. ============================================================================= BUG kmalloc-4096: Poison overwritten ----------------------------------------------------------------------------- INFO: 0xffff810067419060-0xffff810067419667. First byte 0x8 instead of 0x6b INFO: Allocated in dev_alloc_skb+0x18/0x30 age=1118 cpu=1 pid=0 INFO: Freed in skb_release_data+0x85/0xd0 age=1105 cpu=1 pid=3718 INFO: Slab 0xffffe200019d0600 objects=7 used=0 fp=0xffff810067419048 flags=0x40000000000020c3 INFO: Object 0xffff810067419048 @offset=4168 fp=0xffff81006741c120 Bytes b4 0xffff810067419038: 4f 0b 02 00 01 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a O.......ZZZZZZZZ Object 0xffff810067419048: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk Object 0xffff810067419058: 6b 6b 6b 6b 6b 6b 6b 6b 08 42 30 00 00 0b 6b 80 kkkkkkkk.B0...k. Object 0xffff810067419068: f0 5d 00 4f 62 08 a3 64 00 0c 42 16 52 e4 f0 5a 360].Ob.243d..B.R344360Z Object 0xffff810067419078: 68 81 00 00 7b a5 b4 be 7d 3b 8f 53 cd d5 de 12 h...{245264276};.S315325336. Object 0xffff810067419088: 96 10 0b 89 48 54 23 41 0f 4e 2d b9 37 c3 cb 29 ....HT#A.N-2717303313) Object 0xffff810067419098: d1 e0 de 14 8a 57 2a cc 3b 44 0d 78 7a 19 12 15 321340336..W*314;D.xz... Object 0xffff8100674190a8: a9 ec d4 35 a8 10 ec 8c 40 a7 06 0a 51 a7 48 bb 2513543245250.354.@247..Q247H273 Object 0xffff8100674190b8: 3e cf a1 c7 38 60 63 3f 51 15 c7 20 eb ba 65 30 >ϡ3078`c?Q.307.353272e0 Redzone 0xffff81006741a048: bb bb bb bb bb bb bb bb 273273273273273273273273 Padding 0xffff81006741a088: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ Pid: 3297, comm: ath5k_pci Not tainted 2.6.26-rc8-mm1_64 #427 Call Trace: [] print_trailer+0xf6/0x150 [] check_bytes_and_report+0x125/0x180 [] check_object+0xac/0x260 [] __slab_alloc+0x368/0x6d0 [] ? wireless_send_event+0x142/0x310 [] ? __alloc_skb+0x44/0x150 [] ? wireless_send_event+0x142/0x310 [] __kmalloc_track_caller+0xc3/0xf0 [] __alloc_skb+0x6e/0x150 [... stack snipped] FIX kmalloc-4096: Restoring 0xffff810067419060-0xffff810067419667=0x6b FIX kmalloc-4096: Marking all objects used Signed-off-by: Jiri Slaby Acked-by: Nick Kossifidis Cc: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 32 +++++++++++++++++++++++++------- drivers/net/wireless/ath5k/base.h | 2 +- 2 files changed, 26 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index d9769c52734..ed51c4a69d4 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1682,20 +1682,21 @@ ath5k_tasklet_rx(unsigned long data) struct ath5k_rx_status rs = {}; struct sk_buff *skb; struct ath5k_softc *sc = (void *)data; - struct ath5k_buf *bf; + struct ath5k_buf *bf, *bf_last; struct ath5k_desc *ds; int ret; int hdrlen; int pad; spin_lock(&sc->rxbuflock); + if (list_empty(&sc->rxbuf)) { + ATH5K_WARN(sc, "empty rx buf pool\n"); + goto unlock; + } + bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list); do { rxs.flag = 0; - if (unlikely(list_empty(&sc->rxbuf))) { - ATH5K_WARN(sc, "empty rx buf pool\n"); - break; - } bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); BUG_ON(bf->skb == NULL); skb = bf->skb; @@ -1705,8 +1706,24 @@ ath5k_tasklet_rx(unsigned long data) pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr, sc->desc_len, PCI_DMA_FROMDEVICE); - if (unlikely(ds->ds_link == bf->daddr)) /* this is the end */ - break; + /* + * last buffer must not be freed to ensure proper hardware + * function. When the hardware finishes also a packet next to + * it, we are sure, it doesn't use it anymore and we can go on. + */ + if (bf_last == bf) + bf->flags |= 1; + if (bf->flags) { + struct ath5k_buf *bf_next = list_entry(bf->list.next, + struct ath5k_buf, list); + ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc, + &rs); + if (ret) + break; + bf->flags &= ~1; + /* skip the overwritten one (even status is martian) */ + goto next; + } ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs); if (unlikely(ret == -EINPROGRESS)) @@ -1816,6 +1833,7 @@ accept: next: list_move_tail(&bf->list, &sc->rxbuf); } while (ath5k_rxbuf_setup(sc, bf) == 0); +unlock: spin_unlock(&sc->rxbuflock); } diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h index 47f414b09e6..d7e03e6b827 100644 --- a/drivers/net/wireless/ath5k/base.h +++ b/drivers/net/wireless/ath5k/base.h @@ -56,7 +56,7 @@ struct ath5k_buf { struct list_head list; - unsigned int flags; /* tx descriptor flags */ + unsigned int flags; /* rx descriptor flags */ struct ath5k_desc *desc; /* virtual addr of desc */ dma_addr_t daddr; /* physical addr of desc */ struct sk_buff *skb; /* skbuff for buf */ -- cgit v1.2.3 From 10488f8ad62be3b860bad74e60b4fe6ab87aece3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 15 Jul 2008 17:44:19 +0200 Subject: Ath5k: kill tasklets on shutdown Don't forget to kill tasklets on stop to not panic if they fire after freeing some structures. Signed-off-by: Jiri Slaby Acked-by: Nick Kossifidis Cc: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index ed51c4a69d4..c5bf8a2ef5c 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -2342,6 +2342,9 @@ ath5k_stop_hw(struct ath5k_softc *sc) mutex_unlock(&sc->lock); del_timer_sync(&sc->calib_tim); + tasklet_kill(&sc->rxtq); + tasklet_kill(&sc->txtq); + tasklet_kill(&sc->restq); return ret; } -- cgit v1.2.3 From 274c7c3638cd027b46f76d0caef96c1bad8b6701 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 15 Jul 2008 17:44:20 +0200 Subject: Ath5k: flush work Make sure that the irq is not in progress after stop. This means two things: - ensure the intr setting register is set by flushing posted values - call synchronize_irq() after that Also flush stop tx write, inform callers of the tx stop about still pending transfers (unsuccessful stop) and finally don't wait another 3ms in ath5k_rx_stop, since ath5k_hw_stop_rx_dma ensures transfer to be finished. Make sure all writes will be ordered in respect to locks by mmiowb(). Signed-off-by: Jiri Slaby Acked-by: Nick Kossifidis Cc: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 13 +++++++++++-- drivers/net/wireless/ath5k/hw.c | 4 ++++ 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index c5bf8a2ef5c..8e9afb3b3a5 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -43,7 +43,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -1249,6 +1251,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) txq->link = &ds->ds_link; ath5k_hw_tx_start(ah, txq->qnum); + mmiowb(); spin_unlock_bh(&txq->lock); return 0; @@ -1583,7 +1586,6 @@ ath5k_rx_stop(struct ath5k_softc *sc) ath5k_hw_stop_pcu_recv(ah); /* disable PCU */ ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */ ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */ - mdelay(3); /* 3ms is long enough for 1 frame */ ath5k_debug_printrxbuffs(sc, ah); @@ -2258,6 +2260,7 @@ ath5k_init(struct ath5k_softc *sc) ret = 0; done: + mmiowb(); mutex_unlock(&sc->lock); return ret; } @@ -2290,6 +2293,7 @@ ath5k_stop_locked(struct ath5k_softc *sc) if (!test_bit(ATH_STAT_INVALID, sc->status)) { ath5k_led_off(sc); ath5k_hw_set_intr(ah, 0); + synchronize_irq(sc->pdev->irq); } ath5k_txq_cleanup(sc); if (!test_bit(ATH_STAT_INVALID, sc->status)) { @@ -2339,6 +2343,7 @@ ath5k_stop_hw(struct ath5k_softc *sc) } } ath5k_txbuf_free(sc, sc->bbuf); + mmiowb(); mutex_unlock(&sc->lock); del_timer_sync(&sc->calib_tim); @@ -2804,6 +2809,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /* XXX: assoc id is set to 0 for now, mac80211 doesn't have * a clean way of letting us retrieve this yet. */ ath5k_hw_set_associd(ah, ah->ah_bssid, 0); + mmiowb(); } if (conf->changed & IEEE80211_IFCC_BEACON && @@ -2992,6 +2998,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } unlock: + mmiowb(); mutex_unlock(&sc->lock); return ret; } @@ -3065,8 +3072,10 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) ret = ath5k_beacon_setup(sc, sc->bbuf); if (ret) sc->bbuf->skb = NULL; - else + else { ath5k_beacon_config(sc); + mmiowb(); + } end: mutex_unlock(&sc->lock); diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index c6d12c53bda..7ca87a55731 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c @@ -1440,6 +1440,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) /* Stop queue */ ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); + ath5k_hw_reg_read(ah, AR5K_CR); } else { /* * Schedule TX disable and wait until queue is empty @@ -1456,6 +1457,8 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) /* Clear register */ ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD); + if (pending) + return -EBUSY; } /* TODO: Check for success else return error */ @@ -1716,6 +1719,7 @@ enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask) /* ..re-enable interrupts */ ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER); + ath5k_hw_reg_read(ah, AR5K_IER); return old_mask; } -- cgit v1.2.3 From e86600c7b4e9b9b22ba51620613d6159bf5cf504 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 15 Jul 2008 17:44:43 +0200 Subject: Ath5k: fix dma operation Don't sync - coherent mapping (descriptors) - before unmap, it's useless - (wrongly anyway -- for_cpu) beacon skb, it's just mapped, so by the device yet Signed-off-by: Jiri Slaby Acked-by: Nick Kossifidis Cc: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 8e9afb3b3a5..3aa22dc7165 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1704,10 +1704,6 @@ ath5k_tasklet_rx(unsigned long data) skb = bf->skb; ds = bf->desc; - /* TODO only one segment */ - pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr, - sc->desc_len, PCI_DMA_FROMDEVICE); - /* * last buffer must not be freed to ensure proper hardware * function. When the hardware finishes also a packet next to @@ -1771,8 +1767,6 @@ ath5k_tasklet_rx(unsigned long data) goto next; } accept: - pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, - rs.rs_datalen, PCI_DMA_FROMDEVICE); pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, PCI_DMA_FROMDEVICE); bf->skb = NULL; @@ -1860,9 +1854,6 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) list_for_each_entry_safe(bf, bf0, &txq->q, list) { ds = bf->desc; - /* TODO only one segment */ - pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr, - sc->desc_len, PCI_DMA_FROMDEVICE); ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); if (unlikely(ret == -EINPROGRESS)) break; @@ -2035,8 +2026,6 @@ ath5k_beacon_send(struct ath5k_softc *sc) ATH5K_WARN(sc, "beacon queue %u didn't stop?\n", sc->bhalq); /* NB: hw still stops DMA, so proceed */ } - pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, bf->skb->len, - PCI_DMA_TODEVICE); ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr); ath5k_hw_tx_start(ah, sc->bhalq); -- cgit v1.2.3 From 3e4242b99ce46fed82aa7f40ad5a1817a2b3bd45 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 15 Jul 2008 17:44:21 +0200 Subject: Ath5k: suspend/resume fixes - free and re-request irq since it might have changed during suspend - disable and enable msi - don't set D0 state of the device, it's already done by the PCI layer - do restore_state before enable_device, it's safer - check ath5k_init return value Signed-off-by: Jiri Slaby Acked-by: Nick Kossifidis Cc: Luis R. Rodriguez Cc: Jesse Barnes Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 3aa22dc7165..7273e9f5c6d 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -592,6 +592,9 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state) ath5k_led_off(sc); ath5k_stop_hw(sc); + + free_irq(pdev->irq, sc); + pci_disable_msi(pdev); pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); @@ -607,15 +610,12 @@ ath5k_pci_resume(struct pci_dev *pdev) struct ath5k_hw *ah = sc->ah; int i, err; - err = pci_set_power_state(pdev, PCI_D0); - if (err) - return err; + pci_restore_state(pdev); err = pci_enable_device(pdev); if (err) return err; - pci_restore_state(pdev); /* * Suspend/Resume resets the PCI configuration space, so we have to * re-disable the RETRY_TIMEOUT register (0x41) to keep @@ -623,7 +623,17 @@ ath5k_pci_resume(struct pci_dev *pdev) */ pci_write_config_byte(pdev, 0x41, 0); - ath5k_init(sc); + pci_enable_msi(pdev); + + err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); + if (err) { + ATH5K_ERR(sc, "request_irq failed\n"); + goto err_msi; + } + + err = ath5k_init(sc); + if (err) + goto err_irq; ath5k_led_enable(sc); /* @@ -637,6 +647,12 @@ ath5k_pci_resume(struct pci_dev *pdev) ath5k_hw_reset_key(ah, i); return 0; +err_irq: + free_irq(pdev->irq, sc); +err_msi: + pci_disable_msi(pdev); + pci_disable_device(pdev); + return err; } #endif /* CONFIG_PM */ -- cgit v1.2.3 From 734b5aa911dc65f4563048f069dfc631c9aa7de7 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 15 Jul 2008 13:07:16 -0400 Subject: ath5k: use positive logic for HP laptop LEDs Helge Deller reports that HP laptops (NC4010 and NC6000) use active- high signals to turn on the LEDs. Previous code used active-low for all devices. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 7273e9f5c6d..359795d8b48 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -2581,8 +2581,6 @@ ath5k_init_leds(struct ath5k_softc *sc) struct pci_dev *pdev = sc->pdev; char name[ATH5K_LED_MAX_NAME_LEN + 1]; - sc->led_on = 0; /* active low */ - /* * Auto-enable soft led processing for IBM cards and for * 5211 minipci cards. @@ -2591,11 +2589,13 @@ ath5k_init_leds(struct ath5k_softc *sc) pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) { __set_bit(ATH_STAT_LEDSOFT, sc->status); sc->led_pin = 0; + sc->led_on = 0; /* active low */ } /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */ if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) { __set_bit(ATH_STAT_LEDSOFT, sc->status); sc->led_pin = 1; + sc->led_on = 1; /* active high */ } if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) goto out; -- cgit v1.2.3 From 699669f331a9e459713e4327a468db8fbb8cd60f Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Wed, 16 Jul 2008 16:39:56 +0300 Subject: iwl-3945: add #ifdef CONFIG_IWL3945_LEDS to avoid compile warning. When building the wireless-next-2.6 tree with CONFIG_IWL3945 (for building iwl-3945 driver) and where CONFIG_IWL3945_LEDS is not set, we get this warning: drivers/net/wireless/iwlwifi/iwl-3945.c: In function 'iwl3945_pass_packet_to_mac80211': drivers/net/wireless/iwlwifi/iwl-3945.c:633: warning: unused variable 'hdr' This patch adds #ifdef to iwl3945_pass_packet_to_mac80211() to avoid this warning. (The variable 'hdr' is used only if CONFIG_IWL3945_LEDS is set) Signed-off-by: Rami Rosen Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index c2a76785b66..a51e0eaa133 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -630,7 +630,9 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl3945_priv *priv, struct ieee80211_rx_status *stats) { struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data; +#ifdef CONFIG_IWL3945_LEDS struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); +#endif struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); short len = le16_to_cpu(rx_hdr->len); -- cgit v1.2.3 From fb904907fb1a02a64af9f2d1fb1ef35d963231f9 Mon Sep 17 00:00:00 2001 From: Brian Cavagnolo Date: Wed, 16 Jul 2008 12:15:26 -0700 Subject: libertas: check bounds and only use decimal for sysfs persistent features. Some persistent settings were using hex and others decimal. In some cases, values were set in hex but reported in decimal. Confusing. Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/persistcfg.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c index 6d0ff8decaf..3309a9c3cfe 100644 --- a/drivers/net/wireless/libertas/persistcfg.c +++ b/drivers/net/wireless/libertas/persistcfg.c @@ -48,7 +48,7 @@ static ssize_t bootflag_get(struct device *dev, if (ret) return ret; - return snprintf(buf, 12, "0x%x\n", le32_to_cpu(defs.bootflag)); + return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag)); } /** @@ -63,8 +63,8 @@ static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, int ret; memset(&cmd, 0, sizeof(cmd)); - ret = sscanf(buf, "%x", &datum); - if (ret != 1) + ret = sscanf(buf, "%d", &datum); + if ((ret != 1) || (datum > 1)) return -EINVAL; *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum); @@ -91,7 +91,7 @@ static ssize_t boottime_get(struct device *dev, if (ret) return ret; - return snprintf(buf, 12, "0x%x\n", defs.boottime); + return snprintf(buf, 12, "%d\n", defs.boottime); } /** @@ -106,8 +106,8 @@ static ssize_t boottime_set(struct device *dev, int ret; memset(&cmd, 0, sizeof(cmd)); - ret = sscanf(buf, "%x", &datum); - if (ret != 1) + ret = sscanf(buf, "%d", &datum); + if ((ret != 1) || (datum > 255)) return -EINVAL; /* A too small boot time will result in the device booting into @@ -143,7 +143,7 @@ static ssize_t channel_get(struct device *dev, if (ret) return ret; - return snprintf(buf, 12, "0x%x\n", le16_to_cpu(defs.channel)); + return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel)); } /** @@ -154,11 +154,11 @@ static ssize_t channel_set(struct device *dev, struct device_attribute *attr, { struct lbs_private *priv = to_net_dev(dev)->priv; struct cmd_ds_mesh_config cmd; - uint16_t datum; + uint32_t datum; int ret; memset(&cmd, 0, sizeof(cmd)); - ret = sscanf(buf, "%hx", &datum); + ret = sscanf(buf, "%d", &datum); if (ret != 1 || datum < 1 || datum > 11) return -EINVAL; @@ -274,8 +274,8 @@ static ssize_t protocol_id_set(struct device *dev, int ret; memset(&cmd, 0, sizeof(cmd)); - ret = sscanf(buf, "%x", &datum); - if (ret != 1) + ret = sscanf(buf, "%d", &datum); + if ((ret != 1) || (datum > 255)) return -EINVAL; /* fetch all other Information Element parameters */ @@ -328,8 +328,8 @@ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, int ret; memset(&cmd, 0, sizeof(cmd)); - ret = sscanf(buf, "%x", &datum); - if (ret != 1) + ret = sscanf(buf, "%d", &datum); + if ((ret != 1) || (datum > 255)) return -EINVAL; /* fetch all other Information Element parameters */ @@ -382,8 +382,8 @@ static ssize_t capability_set(struct device *dev, struct device_attribute *attr, int ret; memset(&cmd, 0, sizeof(cmd)); - ret = sscanf(buf, "%x", &datum); - if (ret != 1) + ret = sscanf(buf, "%d", &datum); + if ((ret != 1) || (datum > 255)) return -EINVAL; /* fetch all other Information Element parameters */ -- cgit v1.2.3 From c0b6a1c9be3acac0f600072ebc2bc6ad3d8c8f76 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 17 Jul 2008 13:19:24 +0400 Subject: iwlwifi: compilation error when CONFIG_IWLWIFI_DEBUG is not set CC [M] drivers/net/wireless/iwlwifi/iwl-rfkill.o drivers/net/wireless/iwlwifi/iwl-led.c: In function 'iwl_led_brightness_set': drivers/net/wireless/iwlwifi/iwl-led.c:198: error: 'led_type_str' undeclared (first use in this function) drivers/net/wireless/iwlwifi/iwl-led.c:198: error: (Each undeclared identifier is reported only once drivers/net/wireless/iwlwifi/iwl-led.c:198: error: for each function it appears in.) The problem is that led_type_str is defined under CONFIG_IWLWIFI_DEBUG while IWL_DEBUG is a static inline function in this case. Replace it with macro. Signed-off-by: Denis V. Lunev Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debug.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 58384805a49..d6d729e86bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -68,12 +68,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv); #endif #else -static inline void IWL_DEBUG(int level, const char *fmt, ...) -{ -} -static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) -{ -} +#define IWL_DEBUG(level, fmt, args...) +#define IWL_DEBUG_LIMIT(level, fmt, args...) #endif /* CONFIG_IWLWIFI_DEBUG */ -- cgit v1.2.3 From cb9289cb798502a5010c8f1d8d003842cd1449a4 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 18 Jul 2008 10:56:12 +0400 Subject: iwlwifi: small compile warnings without CONFIG_IWLWIFI_DEBUG CC [M] drivers/net/wireless/iwlwifi/iwl-scan.o drivers/net/wireless/iwlwifi/iwl-scan.c: In function 'iwl_rx_scan_complete_notif': drivers/net/wireless/iwlwifi/iwl-scan.c:274: warning: unused variable 'scan_notif' Signed-off-by: Denis V. Lunev Acked-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-scan.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index efc750d2fc5..5a00ac23e2d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -270,6 +270,7 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv, static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { +#ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; @@ -277,6 +278,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, scan_notif->scanned_channels, scan_notif->tsf_low, scan_notif->tsf_high, scan_notif->status); +#endif /* The HW is no longer scanning */ clear_bit(STATUS_SCAN_HW, &priv->status); -- cgit v1.2.3 From bc05116ab33d30342e2b4b1bcc6d6e1184e9df97 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Fri, 18 Jul 2008 11:11:21 -0400 Subject: ath5k: fix recursive locking in ath5k_beacon_update ath5k_beacon_update takes sc->lock upon entry. However, it is only called from within ath5k_config_interface, which already holds the lock. Remove the unnecessary locking from ath5k_beacon_update. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 359795d8b48..3285032727b 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -3065,8 +3065,6 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) ath5k_debug_dump_skb(sc, skb, "BC ", 1); - mutex_lock(&sc->lock); - if (sc->opmode != IEEE80211_IF_TYPE_IBSS) { ret = -EIO; goto end; @@ -3083,7 +3081,6 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) } end: - mutex_unlock(&sc->lock); return ret; } -- cgit v1.2.3 From 256b152b005e319f985f50f2a910a75ba0def74f Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 18 Jul 2008 12:56:59 -0400 Subject: ath5k: don't enable MSI, we cannot handle it yet MSI is a nice thing, but we cannot enable it without changing the interrupt handler. If we do it, we break MSI capable hardware, specifically AR5006 chipset. Signed-off-by: Pavel Roskin Acked-by: Nick Kossifidis Cc: stable Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 3285032727b..1106d1c0629 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -473,9 +473,6 @@ ath5k_pci_probe(struct pci_dev *pdev, /* Set private data */ pci_set_drvdata(pdev, hw); - /* Enable msi for devices that support it */ - pci_enable_msi(pdev); - /* Setup interrupt handler */ ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); if (ret) { @@ -553,7 +550,6 @@ err_ah: err_irq: free_irq(pdev->irq, sc); err_free: - pci_disable_msi(pdev); ieee80211_free_hw(hw); err_map: pci_iounmap(pdev, mem); @@ -575,7 +571,6 @@ ath5k_pci_remove(struct pci_dev *pdev) ath5k_detach(pdev, hw); ath5k_hw_detach(sc->ah); free_irq(pdev->irq, sc); - pci_disable_msi(pdev); pci_iounmap(pdev, sc->iobase); pci_release_region(pdev, 0); pci_disable_device(pdev); -- cgit v1.2.3 From ed06387b44f0501f7298b559dc8ddfcd410c8fa0 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 19 Jul 2008 16:15:42 +0200 Subject: rt2x00: Remove duplicate declaration rt2x00queue_free_skb() was declared twice. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00lib.h | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index f2c9b0e79b5..c5fb3a72cf3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -124,13 +124,6 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); */ void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); -/** - * rt2x00queue_free_skb - free a skb - * @rt2x00dev: Pointer to &struct rt2x00_dev. - * @skb: The skb to free. - */ -void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); - /** * rt2x00queue_write_tx_frame - Write TX frame to hardware * @queue: Queue over which the frame should be send -- cgit v1.2.3 From f2fdbc4847e0d3991474949f21aa439c361391db Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 19 Jul 2008 16:16:12 +0200 Subject: rt2x00: Fix EIFS timing value Olivier reported a difference between the EIFS values used in the legacy driver and the one in the rt2x00 drivers. In rt2x00 the value was ( SIFS + (8 * (IEEE80211_HEADER + ACK_SIZE)) ) which comes down to 314us while the legacy driver uses the value 364us This was caused because EIFS is: SIFS + DIFS + AckTime This patch will fix this by adding the DIFS by the above value, and creating a SHORT_EIFS define which uses the SHORT_DIFS. Reported-by: Olivier Cornu Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 5 ++++- drivers/net/wireless/rt2x00/rt2x00config.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 07b03b3c7ef..73495f0ee13 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -108,7 +108,10 @@ #define SHORT_PIFS ( SIFS + SHORT_SLOT_TIME ) #define DIFS ( PIFS + SLOT_TIME ) #define SHORT_DIFS ( SHORT_PIFS + SHORT_SLOT_TIME ) -#define EIFS ( SIFS + (8 * (IEEE80211_HEADER + ACK_SIZE)) ) +#define EIFS ( SIFS + DIFS + \ + (8 * (IEEE80211_HEADER + ACK_SIZE)) ) +#define SHORT_EIFS ( SIFS + SHORT_DIFS + \ + (8 * (IEEE80211_HEADER + ACK_SIZE)) ) /* * Chipset identification diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index f20ca712504..3f89516e833 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -271,7 +271,7 @@ config: libconf.sifs = SIFS; libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS; libconf.difs = short_slot_time ? SHORT_DIFS : DIFS; - libconf.eifs = EIFS; + libconf.eifs = short_slot_time ? SHORT_EIFS : EIFS; } libconf.conf = conf; -- cgit v1.2.3 From ed0dbeeb92bdb1030bcec67e20b294bd2020cb31 Mon Sep 17 00:00:00 2001 From: Iwo Mergler Date: Sat, 19 Jul 2008 16:16:54 +0200 Subject: rt2x00: Support for large vendor requests Adds an extra rt2x00 vendor request function to support register transfers beyond the CSR_CACHE_SIZE / USB packet size limit. This is useful for firmware uploads, beacon templates and keys, all of which are to large to do with a single USB request. Signed-off-by: Iwo Mergler Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00usb.c | 32 ++++++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2x00usb.h | 21 ++++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 83862e7f7ae..933e6cc9359 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -122,6 +122,38 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev, } EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff); +int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev, + const u8 request, const u8 requesttype, + const u16 offset, void *buffer, + const u16 buffer_length, + const int timeout) +{ + int status = 0; + unsigned char *tb; + u16 off, len, bsize; + + mutex_lock(&rt2x00dev->usb_cache_mutex); + + tb = buffer; + off = offset; + len = buffer_length; + while (len && !status) { + bsize = min_t(u16, CSR_CACHE_SIZE, len); + status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request, + requesttype, off, tb, + bsize, timeout); + + tb += bsize; + len -= bsize; + off += bsize; + } + + mutex_unlock(&rt2x00dev->usb_cache_mutex); + + return status; +} +EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff); + /* * TX data handlers. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index aad794adf52..8d5d4272e88 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -70,7 +70,7 @@ /* * Cache size */ -#define CSR_CACHE_SIZE 8 +#define CSR_CACHE_SIZE 64 #define CSR_CACHE_SIZE_FIRMWARE 64 /* @@ -171,6 +171,25 @@ int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev, const u16 offset, void *buffer, const u16 buffer_length, const int timeout); +/** + * rt2x00usb_vendor_request_large_buff - Send register command to device (buffered) + * @rt2x00dev: Pointer to &struct rt2x00_dev + * @request: USB vendor command (See &enum rt2x00usb_vendor_request) + * @requesttype: Request type &USB_VENDOR_REQUEST_* + * @offset: Register start offset to perform action on + * @buffer: Buffer where information will be read/written to by device + * @buffer_length: Size of &buffer + * @timeout: Operation timeout + * + * This function is used to transfer register data in blocks larger + * then CSR_CACHE_SIZE. Use for firmware upload, keys and beacons. + */ +int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev, + const u8 request, const u8 requesttype, + const u16 offset, void *buffer, + const u16 buffer_length, + const int timeout); + /** * rt2x00usb_vendor_request_sw - Send single register command to device * @rt2x00dev: Pointer to &struct rt2x00_dev -- cgit v1.2.3 From 3e0c1abe748a30bc705a55f71bca8e04a83820f1 Mon Sep 17 00:00:00 2001 From: Iwo Mergler Date: Sat, 19 Jul 2008 16:17:16 +0200 Subject: rt2x00: Large vendor requests for rt73usb firmware upload and beacons Switches rt73usb to use large vendor requests for firmware and beacons. This also fixes the garbled beacon bug. Signed-off-by: Iwo Mergler Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00usb.h | 1 - drivers/net/wireless/rt2x00/rt73usb.c | 40 ++++++++------------------------- 2 files changed, 9 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 8d5d4272e88..ee3875f894a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -71,7 +71,6 @@ * Cache size */ #define CSR_CACHE_SIZE 64 -#define CSR_CACHE_SIZE_FIRMWARE 64 /* * USB request types. diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index b9efa7f76c9..fc320c0409d 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -890,9 +890,6 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, unsigned int i; int status; u32 reg; - const char *ptr = data; - char *cache; - int buflen; /* * Wait for stable hardware. @@ -911,31 +908,12 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, /* * Write firmware to device. - * We setup a seperate cache for this action, - * since we are going to write larger chunks of data - * then normally used cache size. */ - cache = kmalloc(CSR_CACHE_SIZE_FIRMWARE, GFP_KERNEL); - if (!cache) { - ERROR(rt2x00dev, "Failed to allocate firmware cache.\n"); - return -ENOMEM; - } - - for (i = 0; i < len; i += CSR_CACHE_SIZE_FIRMWARE) { - buflen = min_t(int, len - i, CSR_CACHE_SIZE_FIRMWARE); - - memcpy(cache, ptr, buflen); - - rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, - USB_VENDOR_REQUEST_OUT, - FIRMWARE_IMAGE_BASE + i, 0, - cache, buflen, - REGISTER_TIMEOUT32(buflen)); - - ptr += buflen; - } - - kfree(cache); + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, + FIRMWARE_IMAGE_BASE, + data, len, + REGISTER_TIMEOUT32(len)); /* * Send firmware request to device to load firmware, @@ -1374,10 +1352,10 @@ static void rt73usb_write_beacon(struct queue_entry *entry) * Write entire beacon with descriptor to register. */ beacon_base = HW_BEACON_OFFSET(entry->entry_idx); - rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, - USB_VENDOR_REQUEST_OUT, beacon_base, 0, - entry->skb->data, entry->skb->len, - REGISTER_TIMEOUT32(entry->skb->len)); + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, beacon_base, + entry->skb->data, entry->skb->len, + REGISTER_TIMEOUT32(entry->skb->len)); /* * Clean up the beacon skb. -- cgit v1.2.3 From b93ce437eba7e0232683326f30d9d1167a872fad Mon Sep 17 00:00:00 2001 From: Iwo Mergler Date: Sat, 19 Jul 2008 16:17:40 +0200 Subject: rt2x00: Fix the beacon length bug When setting up a beacon template, the length of the beacon is calculated with the assumption that the SKB already contains the Tx descriptor. In the case of beacons it doesn't. This patch undoes the damage by adding the Tx descriptor length to the beacon length. This is safe, because the shortest possible beacon is longer than the Tx header. Signed-off-by: Iwo Mergler Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 12 ++++++++++++ drivers/net/wireless/rt2x00/rt73usb.c | 12 ++++++++++++ 2 files changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 449c8d39348..3078417b326 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1121,6 +1121,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) int pipe = usb_sndbulkpipe(usb_dev, 1); int length; u16 reg; + u32 word, len; /* * Add the descriptor in front of the skb. @@ -1129,6 +1130,17 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len); skbdesc->desc = entry->skb->data; + /* + * Adjust the beacon databyte count. The current number is + * calculated before this function gets called, but falsely + * assumes that the descriptor was already present in the SKB. + */ + rt2x00_desc_read(skbdesc->desc, 0, &word); + len = rt2x00_get_field32(word, TXD_W0_DATABYTE_COUNT); + len += skbdesc->desc_len; + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, len); + rt2x00_desc_write(skbdesc->desc, 0, word); + /* * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index fc320c0409d..866504612e8 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1330,6 +1330,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry) struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); unsigned int beacon_base; u32 reg; + u32 word, len; /* * Add the descriptor in front of the skb. @@ -1338,6 +1339,17 @@ static void rt73usb_write_beacon(struct queue_entry *entry) memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len); skbdesc->desc = entry->skb->data; + /* + * Adjust the beacon databyte count. The current number is + * calculated before this function gets called, but falsely + * assumes that the descriptor was already present in the SKB. + */ + rt2x00_desc_read(skbdesc->desc, 0, &word); + len = rt2x00_get_field32(word, TXD_W0_DATABYTE_COUNT); + len += skbdesc->desc_len; + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, len); + rt2x00_desc_write(skbdesc->desc, 0, word); + /* * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. -- cgit v1.2.3 From 5adf6d63c1697ce1835daf2b5393488a71ee0dca Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 20 Jul 2008 18:03:38 +0200 Subject: rt2x00: Fix QOS sequence counting When IEEE80211_TX_CTL_ASSIGN_SEQ is not set, the driver should disable hardware sequence counting to make sure the mac80211 provided counter is used. This fixes QOS sequence counting, since that is one of the cases where mac80211 provides a seperate sequence counter. By moving the sequence counting code to rt2x00queue we make sure that _all_ frames get the sequence counter, including RTS/CTS and Beacon frames. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00mac.c | 13 ------------- drivers/net/wireless/rt2x00/rt2x00queue.c | 26 ++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2x00queue.h | 2 ++ drivers/net/wireless/rt2x00/rt61pci.c | 3 ++- drivers/net/wireless/rt2x00/rt73usb.c | 3 ++- 5 files changed, 32 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index f1dcbaa80c3..9d346bd2db0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -96,7 +96,6 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; enum data_queue_qid qid = skb_get_queue_mapping(skb); - struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); struct data_queue *queue; u16 frame_control; @@ -152,18 +151,6 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) } } - /* - * XXX: This is as wrong as the old mac80211 code was, - * due to beacons not getting sequence numbers assigned - * properly. - */ - if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - intf->seqno += 0x10; - ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - ieee80211hdr->seq_ctrl |= cpu_to_le16(intf->seqno); - } - if (rt2x00queue_write_tx_frame(queue, skb)) { ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_BUSY; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 7f442030f5a..7b581a370fd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -120,6 +120,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; struct ieee80211_rate *rate = ieee80211_get_tx_rate(rt2x00dev->hw, tx_info); @@ -199,6 +200,31 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, txdesc->ifs = IFS_SIFS; } + /* + * Hardware should insert sequence counter. + * FIXME: We insert a software sequence counter first for + * hardware that doesn't support hardware sequence counting. + * + * This is wrong because beacons are not getting sequence + * numbers assigned properly. + * + * A secondary problem exists for drivers that cannot toggle + * sequence counting per-frame, since those will override the + * sequence counter given by mac80211. + */ + if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + spin_lock(&intf->lock); + + if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)) + intf->seqno += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(intf->seqno); + + spin_unlock(&intf->lock); + + __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); + } + /* * PLCP setup * Length calculation depends on OFDM/CCK rate. diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 8945945c892..a4a8c57004d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -199,6 +199,7 @@ struct txdone_entry_desc { * @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame. * @ENTRY_TXD_CTS_FRAME: This frame is a CTS-to-self frame. * @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate. + * @ENTRY_TXD_GENERATE_SEQ: This frame requires sequence counter. * @ENTRY_TXD_FIRST_FRAGMENT: This is the first frame. * @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment. * @ENTRY_TXD_REQ_TIMESTAMP: Require timestamp to be inserted. @@ -210,6 +211,7 @@ enum txentry_desc_flags { ENTRY_TXD_RTS_FRAME, ENTRY_TXD_CTS_FRAME, ENTRY_TXD_OFDM_RATE, + ENTRY_TXD_GENERATE_SEQ, ENTRY_TXD_FIRST_FRAGMENT, ENTRY_TXD_MORE_FRAG, ENTRY_TXD_REQ_TIMESTAMP, diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index ec4ec65d94f..fbe2a652e01 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1544,7 +1544,8 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); - rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1); + rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, + test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); rt2x00_desc_write(txd, 1, word); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 866504612e8..9761eaaa08b 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1281,7 +1281,8 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); - rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1); + rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, + test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); rt2x00_desc_write(txd, 1, word); rt2x00_desc_read(txd, 2, &word); -- cgit v1.2.3 From e7087a828f8714e464fff18d93618727530dfd89 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 20 Jul 2008 18:03:58 +0200 Subject: rt2x00: Fix memleak when RTS/CTS fails When sending the RTS/CTS frame fails, we should free the skb buffer which was created. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00mac.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 9d346bd2db0..1f83d5fbf6b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -83,6 +83,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, (struct ieee80211_rts *)(skb->data)); if (rt2x00queue_write_tx_frame(queue, skb)) { + dev_kfree_skb_any(skb); WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n"); return NETDEV_TX_BUSY; } -- cgit v1.2.3 From 80c42affad970c8ebc5ebec4681aef8dadf21c32 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 21 Jul 2008 09:58:11 +0200 Subject: drivers/net/wireless/ipw2100.c: Release mutex in error handling code The mutex is released on a successful return, so it would seem that it should be released on an error return as well. The semantic patch finds this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ expression l; @@ mutex_lock(l); ... when != mutex_unlock(l) when any when strict ( if (...) { ... when != mutex_unlock(l) + mutex_unlock(l); return ...; } | mutex_unlock(l); ) // Signed-off-by: Julia Lawall Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2100.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 5bf9e00b070..c6f886ec08a 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -6442,6 +6442,7 @@ static int ipw2100_resume(struct pci_dev *pci_dev) if (err) { printk(KERN_ERR "%s: pci_enable_device failed on resume\n", dev->name); + mutex_unlock(&priv->action_mutex); return err; } pci_restore_state(pci_dev); @@ -7146,7 +7147,7 @@ static int ipw2100_wx_get_rate(struct net_device *dev, err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len); if (err) { IPW_DEBUG_WX("failed querying ordinals.\n"); - return err; + goto done; } switch (val & TX_RATE_MASK) { -- cgit v1.2.3 From 4104863fb4a724723d1d5f3cba9d3c5084087e45 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 21 Jul 2008 11:29:34 +0200 Subject: b43legacy: Release mutex in error handling code The mutex is released on a successful return, so it would seem that it should be released on an error return as well. The semantic patch finds this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ expression l; @@ mutex_lock(l); ... when != mutex_unlock(l) when any when strict ( if (...) { ... when != mutex_unlock(l) + mutex_unlock(l); return ...; } | mutex_unlock(l); ) // Signed-off-by: Julia Lawall Signed-off-by: Michael Buesch Cc: stable Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index cb5ad4f7fb2..2541c81932f 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3845,10 +3845,10 @@ static int b43legacy_resume(struct ssb_device *dev) goto out; } } - mutex_unlock(&wl->mutex); b43legacydbg(wl, "Device resumed.\n"); out: + mutex_unlock(&wl->mutex); return err; } -- cgit v1.2.3 From 74c0ee9b59bdaa81a666d5d58022f847390e4b0c Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 21 Jul 2008 11:52:44 +0200 Subject: rt2x00: Force full register config after start() rt2x00 will only perform configuration changes from mac80211 when the configuration option has changed. This means it keeps track of the current active configuration and will check these values when the config() callback function is used. However this causes breakage when the interface has been brought down and up again, since all stored active values aren't reset while the registers might have. This is for example the case with rt61pci antenna registers which will jump to invalid values when the interface has been started. To make sure a full configuration takes place after the start() callback function, a new flag is added which will be checked during config() and skips the "what's changed" phase. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 1 + drivers/net/wireless/rt2x00/rt2x00dev.c | 7 ++++--- drivers/net/wireless/rt2x00/rt2x00mac.c | 13 ++++++++++++- 3 files changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 73495f0ee13..db2dc976d83 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -600,6 +600,7 @@ enum rt2x00_flags { DEVICE_STARTED_SUSPEND, DEVICE_ENABLED_RADIO, DEVICE_DISABLED_RADIO_HW, + DEVICE_DIRTY_CONFIG, /* * Driver features diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 8c93eb8353b..f42283ad7b0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1013,6 +1013,7 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) rt2x00dev->intf_associated = 0; __set_bit(DEVICE_STARTED, &rt2x00dev->flags); + __set_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags); return 0; } @@ -1237,9 +1238,9 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) /* * Reconfigure device. */ - rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, 1); - if (!rt2x00dev->hw->conf.radio_enabled) - rt2x00lib_disable_radio(rt2x00dev); + retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf); + if (retval) + goto exit; /* * Iterator over each active interface to diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 1f83d5fbf6b..042ab00d8bd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -310,6 +310,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) { struct rt2x00_dev *rt2x00dev = hw->priv; + int force_reconfig; /* * Mac80211 might be calling this function while we are trying @@ -329,7 +330,17 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); } - rt2x00lib_config(rt2x00dev, conf, 0); + /* + * When the DEVICE_DIRTY_CONFIG flag is set, the device has recently + * been started and the configuration must be forced upon the hardware. + * Otherwise registers will not be intialized correctly and could + * result in non-working hardware because essential registers aren't + * initialized. + */ + force_reconfig = + __test_and_clear_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags); + + rt2x00lib_config(rt2x00dev, conf, force_reconfig); /* * Reenable RX only if the radio should be on. -- cgit v1.2.3 From 9c0ab712c7e40b61063431cae74a3e763535a4e7 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 21 Jul 2008 19:06:02 +0200 Subject: rt2x00: Clear queue entry flags during initialization When the queues are being initialized the entry flags fields must be reset to 0. When this does not happen some entries might still be marked as "occupied" after an ifdown & ifup cycle which would trigger errors when the entry is being accessed: phy0 -> rt2x00queue_write_tx_frame: Error - Arrived at non-free entry in the non-full queue 0. Please file bug report to http://rt2x00.serialmonkey.com. This also fixes the mac80211 warning: ------------[ cut here ]------------ WARNING: at net/mac80211/tx.c:1238 ieee80211_master_start_xmit+0x30a/0x350 [mac80211]() which was triggered by the queue error. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00queue.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 7b581a370fd..3b27f6aa860 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -492,9 +492,12 @@ void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev) if (!rt2x00dev->ops->lib->init_rxentry) return; - for (i = 0; i < queue->limit; i++) + for (i = 0; i < queue->limit; i++) { + queue->entries[i].flags = 0; + rt2x00dev->ops->lib->init_rxentry(rt2x00dev, &queue->entries[i]); + } } void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev) @@ -508,9 +511,12 @@ void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev) if (!rt2x00dev->ops->lib->init_txentry) continue; - for (i = 0; i < queue->limit; i++) + for (i = 0; i < queue->limit; i++) { + queue->entries[i].flags = 0; + rt2x00dev->ops->lib->init_txentry(rt2x00dev, &queue->entries[i]); + } } } -- cgit v1.2.3 From 031211049b71619f7e776521963c082ca453d9fd Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 22 Jul 2008 23:50:04 -0700 Subject: drivers/net/wireless/iwlwifi/iwl-led.c: printk fix ia64: drivers/net/wireless/iwlwifi/iwl-led.c: In function `iwl_get_blink_rate': drivers/net/wireless/iwlwifi/iwl-led.c:271: warning: long long int format, s64 arg (arg 6) drivers/net/wireless/iwlwifi/iwl-led.c:271: warning: long long int format, u64 arg (arg 7) We do not know what type the architecture uses to impement u64 and s64, hence we must cast the variables for printing. Cc: Tomas Winkler Cc: John W. Linville Cc: Zhu Yi Signed-off-by: Andrew Morton Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-led.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 899d7a2567a..61250e6a7d1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -268,7 +268,9 @@ static int iwl_get_blink_rate(struct iwl_priv *priv) if (tpt < 0) /* wrapparound */ tpt = -tpt; - IWL_DEBUG_LED("tpt %lld current_tpt %lld\n", tpt, current_tpt); + IWL_DEBUG_LED("tpt %lld current_tpt %llu\n", + (long long)tpt, + (unsigned long long)current_tpt); priv->led_tpt = current_tpt; if (!priv->allow_blinking) -- cgit v1.2.3 From 0b06b2ae0e474fc6378117c832bcd94785a9e975 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Wed, 23 Jul 2008 18:36:38 -0700 Subject: mac80211: fix sparse integer as NULL pointer warning drivers/net/wireless/mac80211_hwsim.c:503:20: warning: Using plain integer as NULL pointer Signed-off-by: Harvey Harrison Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 5816230d58f..248d31a7aa3 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -500,7 +500,7 @@ failed_hw: device_unregister(data->dev); failed_drvdata: ieee80211_free_hw(hw); - hwsim_radios[i] = 0; + hwsim_radios[i] = NULL; failed: mac80211_hwsim_free(); return err; -- cgit v1.2.3 From 1f690d7b549ef9c7424536475501885dd5b54930 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 28 Jul 2008 22:08:18 -0500 Subject: rtl8187: Fix for TX sequence number problem "mac80211: fix TX sequence numbers" broke rtl8187. This patch makes the same kind of fix that was done for rt2x00. Note that this code will have to be reworked for proper sequence numbers on beacons. In addition, the sequence number has been placed in the hardware state, not the vif state. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187.h | 1 + drivers/net/wireless/rtl8187_dev.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index 3afb49f8866..8961901b5c0 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -100,6 +100,7 @@ struct rtl8187_priv { struct usb_device *udev; u32 rx_conf; u16 txpwr_base; + u16 seqno; u8 asic_rev; u8 is_rtl8187b; enum { diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index d3067b1216c..7ff03aca251 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -169,6 +169,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct rtl8187_priv *priv = dev->priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; unsigned int ep; void *buf; struct urb *urb; @@ -234,6 +235,20 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) ep = epmap[skb_get_queue_mapping(skb)]; } + /* FIXME: The sequence that follows is needed for this driver to + * work with mac80211 since "mac80211: fix TX sequence numbers". + * As with the temporary code in rt2x00, changes will be needed + * to get proper sequence numbers on beacons. In addition, this + * patch places the sequence number in the hardware state, which + * limits us to a single virtual state. + */ + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + priv->seqno += 0x10; + ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno); + } + info->driver_data[0] = dev; info->driver_data[1] = urb; -- cgit v1.2.3 From 0ccd58fc03f40529f66190b1a41e92a732d2bda8 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 28 Jul 2008 22:25:08 -0500 Subject: rtl8187: Improve wireless statistics for RTL8187B Wireless statistics produced by the RTL8187B driver are not particularly informative about the strength of the received signal. From the data sheet provided by Realtek, I discovered that certain parts of the RX header should have the information necessary to calculate signal quality and strength. With testing, it became clear that most of these quantities were very jittery - only the AGC correlated with the signals expected from nearby AP's. As a result, the quality and strength are derived from the agc value. The scaling has been determined so that the numbers are close to those obtained by b43 under the same conditions. The results are qualitatively correct. Statistics derived for the RTL8187 have not been changed. The RX header variables have been renamed to match the quantites described in the Realtek data sheet. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187.h | 10 +++-- drivers/net/wireless/rtl8187_dev.c | 78 +++++++++++++++++++++++--------------- 2 files changed, 54 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index 8961901b5c0..1b0d750f662 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -47,11 +47,13 @@ struct rtl8187_rx_hdr { struct rtl8187b_rx_hdr { __le32 flags; __le64 mac_time; - u8 noise; - u8 signal; + u8 sq; + u8 rssi; u8 agc; - u8 reserved; - __le32 unused; + u8 flags2; + __le16 snr_long2end; + s8 pwdb_g12; + u8 fot; } __attribute__((packed)); /* {rtl8187,rtl8187b}_tx_info is in skb */ diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 7ff03aca251..177988efd66 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -272,6 +272,7 @@ static void rtl8187_rx_cb(struct urb *urb) struct ieee80211_rx_status rx_status = { 0 }; int rate, signal; u32 flags; + u32 quality; spin_lock(&priv->rx_queue.lock); if (skb->next) @@ -295,44 +296,57 @@ static void rtl8187_rx_cb(struct urb *urb) flags = le32_to_cpu(hdr->flags); signal = hdr->signal & 0x7f; rx_status.antenna = (hdr->signal >> 7) & 1; - rx_status.signal = signal; rx_status.noise = hdr->noise; rx_status.mactime = le64_to_cpu(hdr->mac_time); - priv->signal = signal; priv->quality = signal; + rx_status.qual = priv->quality; priv->noise = hdr->noise; + rate = (flags >> 20) & 0xF; + if (rate > 3) { /* OFDM rate */ + if (signal > 90) + signal = 90; + else if (signal < 25) + signal = 25; + signal = 90 - signal; + } else { /* CCK rate */ + if (signal > 95) + signal = 95; + else if (signal < 30) + signal = 30; + signal = 95 - signal; + } + rx_status.signal = signal; + priv->signal = signal; } else { struct rtl8187b_rx_hdr *hdr = (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); + /* The Realtek datasheet for the RTL8187B shows that the RX + * header contains the following quantities: signal quality, + * RSSI, AGC, the received power in dB, and the measured SNR. + * In testing, none of these quantities show qualitative + * agreement with AP signal strength, except for the AGC, + * which is inversely proportional to the strength of the + * signal. In the following, the quality and signal strength + * are derived from the AGC. The arbitrary scaling constants + * are chosen to make the results close to the values obtained + * for a BCM4312 using b43 as the driver. The noise is ignored + * for now. + */ flags = le32_to_cpu(hdr->flags); - signal = hdr->agc >> 1; - rx_status.antenna = (hdr->signal >> 7) & 1; - rx_status.signal = 64 - min(hdr->noise, (u8)64); - rx_status.noise = hdr->noise; + quality = 170 - hdr->agc; + if (quality > 100) + quality = 100; + signal = 14 - hdr->agc / 2; + rx_status.qual = quality; + priv->quality = quality; + rx_status.signal = signal; + priv->signal = signal; + rx_status.antenna = (hdr->rssi >> 7) & 1; rx_status.mactime = le64_to_cpu(hdr->mac_time); - priv->signal = hdr->signal; - priv->quality = hdr->agc >> 1; - priv->noise = hdr->noise; + rate = (flags >> 20) & 0xF; } skb_trim(skb, flags & 0x0FFF); - rate = (flags >> 20) & 0xF; - if (rate > 3) { /* OFDM rate */ - if (signal > 90) - signal = 90; - else if (signal < 25) - signal = 25; - signal = 90 - signal; - } else { /* CCK rate */ - if (signal > 95) - signal = 95; - else if (signal < 30) - signal = 30; - signal = 95 - signal; - } - - rx_status.qual = priv->quality; - rx_status.signal = signal; rx_status.rate_idx = rate; rx_status.freq = dev->conf.channel->center_freq; rx_status.band = dev->conf.channel->band; @@ -1030,9 +1044,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, priv->mode = IEEE80211_IF_TYPE_MNTR; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_SIGNAL_UNSPEC; - dev->max_signal = 65; + IEEE80211_HW_RX_INCLUDES_FCS; eeprom.data = dev; eeprom.register_read = rtl8187_eeprom_register_read; @@ -1147,10 +1159,16 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, (*channel++).hw_value = txpwr >> 8; } - if (priv->is_rtl8187b) + if (priv->is_rtl8187b) { printk(KERN_WARNING "rtl8187: 8187B chip detected. Support " "is EXPERIMENTAL, and could damage your\n" " hardware, use at your own risk\n"); + dev->flags |= IEEE80211_HW_SIGNAL_DBM; + } else { + dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC; + dev->max_signal = 65; + } + if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) printk(KERN_INFO "rtl8187: inconsistency between id with OEM" " info!\n"); -- cgit v1.2.3 From d0f09804144fd9471a13cf4d80e66842c7fa114f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 29 Jul 2008 11:32:07 +0200 Subject: mac80211: partially fix skb->cb use This patch fixes mac80211 to not use the skb->cb over the queue step from virtual interfaces to the master. The patch also, for now, disables aggregation because that would still require requeuing, will fix that in a separate patch. There are two other places (software requeue and powersaving stations) where requeue can happen, but that is not currently used by any drivers/not possible to use respectively. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 2 +- drivers/net/wireless/b43/xmit.c | 2 +- drivers/net/wireless/b43legacy/xmit.c | 2 +- drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 1106d1c0629..ff3fad794b6 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1237,7 +1237,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) pktlen = skb->len; - if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) { + if (info->control.hw_key) { keyidx = info->control.hw_key->hw_key_idx; pktlen += info->control.icv_len; } diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 8d54502222a..9dda8169f7c 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -192,7 +192,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, const struct b43_phy *phy = &dev->phy; const struct ieee80211_hdr *wlhdr = (const struct ieee80211_hdr *)fragment_data; - int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)); + int use_encryption = !!info->control.hw_key; __le16 fctl = wlhdr->frame_control; struct ieee80211_rate *fbrate; u8 rate, rate_fb; diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index e969ed8d412..68e1f8c7872 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -192,7 +192,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, u16 cookie) { const struct ieee80211_hdr *wlhdr; - int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)); + int use_encryption = !!info->control.hw_key; u16 fctl; u8 rate; struct ieee80211_rate *rate_fb; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 9b50b1052b0..f72cd0bf6aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -906,7 +906,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) * first entry */ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); - if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) + if (info->control.hw_key) iwl_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id); /* Set up TFD's 2nd entry to point directly to remainder of skb, diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 05121f395c4..7c82ecfa30a 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2667,7 +2667,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) * first entry */ iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); - if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) + if (info->control.hw_key) iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, 0); /* Set up TFD's 2nd entry to point directly to remainder of skb, diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 042ab00d8bd..c3ee4ecba79 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -63,7 +63,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, */ memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb)); rts_info = IEEE80211_SKB_CB(skb); - rts_info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT; + rts_info->control.hw_key = NULL; rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS; rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT; rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS; -- cgit v1.2.3 From 77bbadd5ea893f364a0d1879723037678a03725c Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Tue, 29 Jul 2008 13:31:47 +0200 Subject: PS3: gelic: use unsigned long for irqflags The semantic patch I used was this: @@ expression lock; identifier flags; expression subclass; @@ - unsigned int flags; + unsigned long flags; ... <+... ( spin_lock_irqsave(lock, flags) | _spin_lock_irqsave(lock) | spin_unlock_irqrestore(lock, flags) | _spin_unlock_irqrestore(lock, flags) | read_lock_irqsave(lock, flags) | _read_lock_irqsave(lock) | read_unlock_irqrestore(lock, flags) | _read_unlock_irqrestore(lock, flags) | write_lock_irqsave(lock, flags) | _write_lock_irqsave(lock) | write_unlock_irqrestore(lock, flags) | _write_unlock_irqrestore(lock, flags) | spin_lock_irqsave_nested(lock, flags, subclass) | _spin_lock_irqsave_nested(lock, subclass) | spin_unlock_irqrestore(lock, flags) | _spin_unlock_irqrestore(lock, flags) | _raw_spin_lock_flags(lock, flags) | __raw_spin_lock_flags(lock, flags) ) ...+> This patch was generated using the Coccinelle framework. Cc: Masakazu Mokuno Cc: Julia Lawall Cc: Alexey Dobriyan Signed-off-by: Vegard Nossum Signed-off-by: John W. Linville --- drivers/net/ps3_gelic_wireless.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index 6b2dee0cf3a..a834b52a6a2 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -1024,7 +1024,7 @@ static int gelic_wl_set_encode(struct net_device *netdev, struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); struct iw_point *enc = &data->encoding; __u16 flags; - unsigned int irqflag; + unsigned long irqflag; int key_index, index_specified; int ret = 0; @@ -1097,7 +1097,7 @@ static int gelic_wl_get_encode(struct net_device *netdev, { struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); struct iw_point *enc = &data->encoding; - unsigned int irqflag; + unsigned long irqflag; unsigned int key_index, index_specified; int ret = 0; @@ -1215,7 +1215,7 @@ static int gelic_wl_set_encodeext(struct net_device *netdev, struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; __u16 alg; __u16 flags; - unsigned int irqflag; + unsigned long irqflag; int key_index; int ret = 0; @@ -1303,7 +1303,7 @@ static int gelic_wl_get_encodeext(struct net_device *netdev, struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); struct iw_point *enc = &data->encoding; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - unsigned int irqflag; + unsigned long irqflag; int key_index; int ret = 0; int max_key_len; @@ -1426,7 +1426,7 @@ static int gelic_wl_priv_set_psk(struct net_device *net_dev, { struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev)); unsigned int len; - unsigned int irqflag; + unsigned long irqflag; int ret = 0; pr_debug("%s:<- len=%d\n", __func__, data->data.length); @@ -1467,7 +1467,7 @@ static int gelic_wl_priv_get_psk(struct net_device *net_dev, { struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev)); char *p; - unsigned int irqflag; + unsigned long irqflag; unsigned int i; pr_debug("%s:<-\n", __func__); -- cgit v1.2.3 From 22ae03a190011fa2241e68a6c51369d78039348e Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Fri, 25 Jul 2008 15:31:29 -0400 Subject: forcedeth bug fix: realtek phy 8211c errata This patch adds support for the realtek 8211c phy. The driver must perform a hardware reset of the phy due to an errata where the phy could not detect the link. Signed-off-by: Ayaz Abdulla Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 64 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 4ed89fa9ae4..01b38b092c7 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -333,6 +333,7 @@ enum { NvRegPowerState2 = 0x600, #define NVREG_POWERSTATE2_POWERUP_MASK 0x0F11 #define NVREG_POWERSTATE2_POWERUP_REV_A3 0x0001 +#define NVREG_POWERSTATE2_PHY_RESET 0x0004 }; /* Big endian: should work, but is untested */ @@ -529,6 +530,7 @@ union ring_type { #define PHY_REALTEK_INIT_REG4 0x14 #define PHY_REALTEK_INIT_REG5 0x18 #define PHY_REALTEK_INIT_REG6 0x11 +#define PHY_REALTEK_INIT_REG7 0x01 #define PHY_REALTEK_INIT1 0x0000 #define PHY_REALTEK_INIT2 0x8e00 #define PHY_REALTEK_INIT3 0x0001 @@ -537,6 +539,9 @@ union ring_type { #define PHY_REALTEK_INIT6 0xf5c7 #define PHY_REALTEK_INIT7 0x1000 #define PHY_REALTEK_INIT8 0x0003 +#define PHY_REALTEK_INIT9 0x0008 +#define PHY_REALTEK_INIT10 0x0005 +#define PHY_REALTEK_INIT11 0x0200 #define PHY_REALTEK_INIT_MSK1 0x0003 #define PHY_GIGABIT 0x0100 @@ -1149,6 +1154,42 @@ static int phy_init(struct net_device *dev) return PHY_ERROR; } } + if (np->phy_model == PHY_MODEL_REALTEK_8211 && + np->phy_rev == PHY_REV_REALTEK_8211C) { + u32 powerstate = readl(base + NvRegPowerState2); + + /* need to perform hw phy reset */ + powerstate |= NVREG_POWERSTATE2_PHY_RESET; + writel(powerstate, base + NvRegPowerState2); + msleep(25); + + powerstate &= ~NVREG_POWERSTATE2_PHY_RESET; + writel(powerstate, base + NvRegPowerState2); + msleep(25); + + reg = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ); + reg |= PHY_REALTEK_INIT9; + if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, reg)) { + printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); + return PHY_ERROR; + } + if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT10)) { + printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); + return PHY_ERROR; + } + reg = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG7, MII_READ); + if (!(reg & PHY_REALTEK_INIT11)) { + reg |= PHY_REALTEK_INIT11; + if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG7, reg)) { + printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); + return PHY_ERROR; + } + } + if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) { + printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); + return PHY_ERROR; + } + } if (np->phy_model == PHY_MODEL_REALTEK_8201) { if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 || np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 || @@ -1201,12 +1242,23 @@ static int phy_init(struct net_device *dev) mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); mii_control |= BMCR_ANENABLE; - /* reset the phy - * (certain phys need bmcr to be setup with reset) - */ - if (phy_reset(dev, mii_control)) { - printk(KERN_INFO "%s: phy reset failed\n", pci_name(np->pci_dev)); - return PHY_ERROR; + if (np->phy_oui == PHY_OUI_REALTEK && + np->phy_model == PHY_MODEL_REALTEK_8211 && + np->phy_rev == PHY_REV_REALTEK_8211C) { + /* start autoneg since we already performed hw reset above */ + mii_control |= BMCR_ANRESTART; + if (mii_rw(dev, np->phyaddr, MII_BMCR, mii_control)) { + printk(KERN_INFO "%s: phy init failed\n", pci_name(np->pci_dev)); + return PHY_ERROR; + } + } else { + /* reset the phy + * (certain phys need bmcr to be setup with reset) + */ + if (phy_reset(dev, mii_control)) { + printk(KERN_INFO "%s: phy reset failed\n", pci_name(np->pci_dev)); + return PHY_ERROR; + } } /* phy vendor specific configuration */ -- cgit v1.2.3 From d7b843d393cec677583e1aa971df09b140dcfd5e Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 27 Jul 2008 22:45:03 +0800 Subject: Blackfin EMAC Driver: add proper __devinit/__devexit markings Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Jeff Garzik --- drivers/net/bfin_mac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index a8ec60e1ed7..de777c28ec6 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -955,7 +955,7 @@ static int bfin_mac_close(struct net_device *dev) return 0; } -static int __init bfin_mac_probe(struct platform_device *pdev) +static int __devinit bfin_mac_probe(struct platform_device *pdev) { struct net_device *ndev; struct bfin_mac_local *lp; @@ -1081,7 +1081,7 @@ out_err_probe_mac: return rc; } -static int bfin_mac_remove(struct platform_device *pdev) +static int __devexit bfin_mac_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct bfin_mac_local *lp = netdev_priv(ndev); @@ -1128,7 +1128,7 @@ static int bfin_mac_resume(struct platform_device *pdev) static struct platform_driver bfin_mac_driver = { .probe = bfin_mac_probe, - .remove = bfin_mac_remove, + .remove = __devexit_p(bfin_mac_remove), .resume = bfin_mac_resume, .suspend = bfin_mac_suspend, .driver = { -- cgit v1.2.3 From a50c0c05c3bdead1ac405ca8cefd8dc290043933 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Sun, 27 Jul 2008 22:45:04 +0800 Subject: Blackfin EMAC Driver: enable TXDWA new feature for new silicon (rev > 0.2) Signed-off-by: Bryan Wu Signed-off-by: Jeff Garzik --- drivers/net/bfin_mac.c | 103 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index de777c28ec6..ab728006cfa 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -605,36 +605,87 @@ adjust_head: static int bfin_mac_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { - unsigned int data; + u16 *data; current_tx_ptr->skb = skb; - /* - * Is skb->data always 16-bit aligned? - * Do we need to memcpy((char *)(tail->packet + 2), skb->data, len)? - */ - if ((((unsigned int)(skb->data)) & 0x02) == 2) { - /* move skb->data to current_tx_ptr payload */ - data = (unsigned int)(skb->data) - 2; - *((unsigned short *)data) = (unsigned short)(skb->len); - current_tx_ptr->desc_a.start_addr = (unsigned long)data; - /* this is important! */ - blackfin_dcache_flush_range(data, (data + (skb->len)) + 2); - + if (ANOMALY_05000285) { + /* + * TXDWA feature is not avaible to older revision < 0.3 silicon + * of BF537 + * + * Only if data buffer is ODD WORD alignment, we do not + * need to memcpy + */ + u32 data_align = (u32)(skb->data) & 0x3; + if (data_align == 0x2) { + /* move skb->data to current_tx_ptr payload */ + data = (u16 *)(skb->data) - 1; + *data = (u16)(skb->len); + current_tx_ptr->desc_a.start_addr = (u32)data; + /* this is important! */ + blackfin_dcache_flush_range((u32)data, + (u32)((u8 *)data + skb->len + 4)); + } else { + *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len); + memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data, + skb->len); + current_tx_ptr->desc_a.start_addr = + (u32)current_tx_ptr->packet; + if (current_tx_ptr->status.status_word != 0) + current_tx_ptr->status.status_word = 0; + blackfin_dcache_flush_range( + (u32)current_tx_ptr->packet, + (u32)(current_tx_ptr->packet + skb->len + 2)); + } } else { - *((unsigned short *)(current_tx_ptr->packet)) = - (unsigned short)(skb->len); - memcpy((char *)(current_tx_ptr->packet + 2), skb->data, - (skb->len)); - current_tx_ptr->desc_a.start_addr = - (unsigned long)current_tx_ptr->packet; - if (current_tx_ptr->status.status_word != 0) - current_tx_ptr->status.status_word = 0; - blackfin_dcache_flush_range((unsigned int)current_tx_ptr-> - packet, - (unsigned int)(current_tx_ptr-> - packet + skb->len) + - 2); + /* + * TXDWA feature is avaible to revision < 0.3 silicon of + * BF537 and always avaible to BF52x + */ + u32 data_align = (u32)(skb->data) & 0x3; + if (data_align == 0x0) { + u16 sysctl = bfin_read_EMAC_SYSCTL(); + sysctl |= TXDWA; + bfin_write_EMAC_SYSCTL(sysctl); + + /* move skb->data to current_tx_ptr payload */ + data = (u16 *)(skb->data) - 2; + *data = (u16)(skb->len); + current_tx_ptr->desc_a.start_addr = (u32)data; + /* this is important! */ + blackfin_dcache_flush_range( + (u32)data, + (u32)((u8 *)data + skb->len + 4)); + } else if (data_align == 0x2) { + u16 sysctl = bfin_read_EMAC_SYSCTL(); + sysctl &= ~TXDWA; + bfin_write_EMAC_SYSCTL(sysctl); + + /* move skb->data to current_tx_ptr payload */ + data = (u16 *)(skb->data) - 1; + *data = (u16)(skb->len); + current_tx_ptr->desc_a.start_addr = (u32)data; + /* this is important! */ + blackfin_dcache_flush_range( + (u32)data, + (u32)((u8 *)data + skb->len + 4)); + } else { + u16 sysctl = bfin_read_EMAC_SYSCTL(); + sysctl &= ~TXDWA; + bfin_write_EMAC_SYSCTL(sysctl); + + *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len); + memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data, + skb->len); + current_tx_ptr->desc_a.start_addr = + (u32)current_tx_ptr->packet; + if (current_tx_ptr->status.status_word != 0) + current_tx_ptr->status.status_word = 0; + blackfin_dcache_flush_range( + (u32)current_tx_ptr->packet, + (u32)(current_tx_ptr->packet + skb->len + 2)); + } } /* enable this packet's dma */ -- cgit v1.2.3 From ee02fee8f698aee72f43b3ee5fd818393b110402 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Sun, 27 Jul 2008 22:45:05 +0800 Subject: Blackfin EMAC Driver: Functional power management support Reprogram MAC address after resume from Suspend Mem (Blackfin Hibernate looses all CORE and SYSTEM register content) Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu Signed-off-by: Jeff Garzik --- drivers/net/bfin_mac.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index ab728006cfa..70c465db17c 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -971,6 +971,7 @@ static int bfin_mac_open(struct net_device *dev) phy_start(lp->phydev); phy_write(lp->phydev, MII_BMCR, BMCR_RESET); setup_system_regs(dev); + setup_mac_addr(dev->dev_addr); bfin_mac_disable(); bfin_mac_enable(); pr_debug("hardware init finished\n"); -- cgit v1.2.3 From 8051367586314ab005dacead790a3b2e4e3dcc58 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Sat, 26 Jul 2008 15:40:56 -0500 Subject: cxgb3: Allow 64KB firmware images. Starting with FW version 7.0, the driver needs to allow larger images. Signed-off-by: Steve Wise Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/t3_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 47d51788a46..04c0e90119a 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -683,7 +683,7 @@ enum { SF_ERASE_SECTOR = 0xd8, /* erase sector */ FW_FLASH_BOOT_ADDR = 0x70000, /* start address of FW in flash */ - FW_VERS_ADDR = 0x77ffc, /* flash address holding FW version */ + FW_VERS_ADDR = 0x7fffc, /* flash address holding FW version */ FW_MIN_SIZE = 8 /* at least version and csum */ }; -- cgit v1.2.3 From 74dfd9fb0ae390027cb5a908ab065a21158105d5 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 25 Jul 2008 11:46:46 -0700 Subject: blackfin_mac: unneeded assignment skb->dev is set by eth_type_trans already. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/bfin_mac.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 70c465db17c..3db7db1828e 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -742,7 +742,6 @@ static void bfin_mac_rx(struct net_device *dev) (unsigned long)skb->tail); dev->last_rx = jiffies; - skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); #if defined(BFIN_MAC_CSUM_OFFLOAD) skb->csum = current_rx_ptr->status.ip_payload_csum; -- cgit v1.2.3 From c7b7b042068cd12b8b155722d24686f70b88ced1 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 24 Jul 2008 17:47:56 -0700 Subject: enc28j60: don't specify (wrong) IRQ type Recent changes to the IRQ framework have made passing the wrong trigger type to request_irq() become a fatal error. In the case of the enc28j60 driver, it stopped working in my test harness. (Specifically: the signal detects "pin change" events, both edges, not just falling edges. Similarly, other boards might route it through an inverter. Trigger type are board-specific.) This fixes that problem by the usual fix of expecting board setup code to have set up the correct IRQ trigger type. The best known example of that being x86 setup. Signed-off-by: David Brownell Signed-off-by: Jeff Garzik --- drivers/net/enc28j60.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index c05cb159c77..aa0bf6e1c69 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -1547,8 +1547,10 @@ static int __devinit enc28j60_probe(struct spi_device *spi) random_ether_addr(dev->dev_addr); enc28j60_set_hw_macaddr(dev); - ret = request_irq(spi->irq, enc28j60_irq, IRQF_TRIGGER_FALLING, - DRV_NAME, priv); + /* Board setup must set the relevant edge trigger type; + * level triggers won't currently work. + */ + ret = request_irq(spi->irq, enc28j60_irq, 0, DRV_NAME, priv); if (ret < 0) { if (netif_msg_probe(priv)) dev_err(&spi->dev, DRV_NAME ": request irq %d failed " -- cgit v1.2.3 From dc56e634c807c6be69be8af919f20a746197b87d Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 22 Jul 2008 16:27:20 -0300 Subject: S2io: fix statistics flush after a MTU change On s2io driver, when you change the interface MTU, it invokes a card reset, which flush some statistics. This patch solves this problem, and also set the net_device->stats as the default statistics structure, instead of s2io_nic->stats. To do that, s2io_nic->stats turned into a staging area, where is saved statistics of the last hardware statistics query. So, the difference between the current hardware statistics and s2io_nic->stats, is the value that should be summed up, in order to get the correct statistics value, even after a reset. Signed-off-by: Breno Leitao Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 86d77d05190..a2b073097e5 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -3143,7 +3143,7 @@ static void tx_intr_handler(struct fifo_info *fifo_data) pkt_cnt++; /* Updating the statistics block */ - nic->stats.tx_bytes += skb->len; + nic->dev->stats.tx_bytes += skb->len; nic->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; dev_kfree_skb_irq(skb); @@ -4896,25 +4896,42 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev) /* Configure Stats for immediate updt */ s2io_updt_stats(sp); + /* Using sp->stats as a staging area, because reset (due to mtu + change, for example) will clear some hardware counters */ + dev->stats.tx_packets += + le32_to_cpu(mac_control->stats_info->tmac_frms) - + sp->stats.tx_packets; sp->stats.tx_packets = le32_to_cpu(mac_control->stats_info->tmac_frms); + dev->stats.tx_errors += + le32_to_cpu(mac_control->stats_info->tmac_any_err_frms) - + sp->stats.tx_errors; sp->stats.tx_errors = le32_to_cpu(mac_control->stats_info->tmac_any_err_frms); + dev->stats.rx_errors += + le64_to_cpu(mac_control->stats_info->rmac_drop_frms) - + sp->stats.rx_errors; sp->stats.rx_errors = le64_to_cpu(mac_control->stats_info->rmac_drop_frms); + dev->stats.multicast = + le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms) - + sp->stats.multicast; sp->stats.multicast = le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms); + dev->stats.rx_length_errors = + le64_to_cpu(mac_control->stats_info->rmac_long_frms) - + sp->stats.rx_length_errors; sp->stats.rx_length_errors = le64_to_cpu(mac_control->stats_info->rmac_long_frms); /* collect per-ring rx_packets and rx_bytes */ - sp->stats.rx_packets = sp->stats.rx_bytes = 0; + dev->stats.rx_packets = dev->stats.rx_bytes = 0; for (i = 0; i < config->rx_ring_num; i++) { - sp->stats.rx_packets += mac_control->rings[i].rx_packets; - sp->stats.rx_bytes += mac_control->rings[i].rx_bytes; + dev->stats.rx_packets += mac_control->rings[i].rx_packets; + dev->stats.rx_bytes += mac_control->rings[i].rx_bytes; } - return (&sp->stats); + return (&dev->stats); } /** @@ -7419,7 +7436,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) if (err_mask != 0x5) { DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%x\n", dev->name, err_mask); - sp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; dev_kfree_skb(skb); -- cgit v1.2.3 From 11c675cef2fbe471dc6103a89b156e65c3630f3a Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 23 May 2008 16:22:42 +1000 Subject: ipmi/powerpc: Use linux/of_{device,platform}.h instead of asm Drivers should not include the asm variants anymore Signed-off-by: Stephen Rothwell Signed-off-by: Benjamin Herrenschmidt --- drivers/char/ipmi/ipmi_si_intf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 192688344ed..f52931e1c16 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -66,8 +66,8 @@ #include #ifdef CONFIG_PPC_OF -#include -#include +#include +#include #endif #define PFX "ipmi_si: " -- cgit v1.2.3 From 9842727da7d95d8249087148048cc571f967c023 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 28 Jul 2008 11:29:56 +1000 Subject: ide/powermac: Fix use of uninitialized pointer on media-bay The current ide-pmac calls media_bay_set_ide_infos() with an uninitialized "hwif" argument. The proper fix is to split the allocation of the hwif from its registration in order to properly setup the mediabay informations before registration. Acked-by: Bartlomiej Zolnierkiewicz Signed-off-by: Benjamin Herrenschmidt --- drivers/ide/ppc/pmac.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index c521bf6e1bf..fa2be26272d 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -1086,6 +1086,11 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw) /* Make sure we have sane timings */ sanitize_timings(pmif); + host = ide_host_alloc(&d, hws); + if (host == NULL) + return -ENOMEM; + hwif = host->ports[0]; + #ifndef CONFIG_PPC64 /* XXX FIXME: Media bay stuff need re-organizing */ if (np->parent && np->parent->name @@ -1119,11 +1124,11 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw) pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id, pmif->mediabay ? " (mediabay)" : "", hw->irq); - rc = ide_host_add(&d, hws, &host); - if (rc) + rc = ide_host_register(host, &d, hws); + if (rc) { + ide_host_free(host); return rc; - - hwif = host->ports[0]; + } return 0; } -- cgit v1.2.3 From 38c080ffa9c1b840390832b42ce8621464ab9f97 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Tue, 29 Jul 2008 23:59:20 -0700 Subject: niu: Fix error checking in niu_ethflow_to_class. The callers of niu_ethflow_to_class expect zero as error, but it returns -1 instead. Signed-off-by: Andreas Schwab Signed-off-by: David S. Miller --- drivers/net/niu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 8ee7d7bb951..e4765b713ab 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -6417,7 +6417,7 @@ static int niu_ethflow_to_class(int flow_type, u64 *class) *class = CLASS_CODE_SCTP_IPV6; break; default: - return -1; + return 0; } return 1; -- cgit v1.2.3 From 16d78bc255a55d16c0888dde336978d633e80b01 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Mon, 14 Jul 2008 09:07:32 +0200 Subject: dm9601: don't do usb transfers of data on stack dm_{read,write}() were doing USB transfers of data on stack, which isn't allowed. Fix it by kmalloc'ing a temporary buffer. Clean up the error handling for short transfers while we're at it. Signed-off-by: Peter Korsgaard Acked-by: David Brownell Signed-off-by: Jeff Garzik --- drivers/net/usb/dm9601.c | 52 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index f7319d32691..78df2be8a72 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -55,12 +55,28 @@ static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data) { + void *buf; + int err = -ENOMEM; + devdbg(dev, "dm_read() reg=0x%02x length=%d", reg, length); - return usb_control_msg(dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - DM_READ_REGS, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, reg, data, length, USB_CTRL_SET_TIMEOUT); + + buf = kmalloc(length, GFP_KERNEL); + if (!buf) + goto out; + + err = usb_control_msg(dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + DM_READ_REGS, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, reg, buf, length, USB_CTRL_SET_TIMEOUT); + if (err == length) + memcpy(data, buf, length); + else if (err >= 0) + err = -EINVAL; + kfree(buf); + + out: + return err; } static int dm_read_reg(struct usbnet *dev, u8 reg, u8 *value) @@ -70,12 +86,28 @@ static int dm_read_reg(struct usbnet *dev, u8 reg, u8 *value) static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data) { + void *buf = NULL; + int err = -ENOMEM; + devdbg(dev, "dm_write() reg=0x%02x, length=%d", reg, length); - return usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - DM_WRITE_REGS, - USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE, - 0, reg, data, length, USB_CTRL_SET_TIMEOUT); + + if (data) { + buf = kmalloc(length, GFP_KERNEL); + if (!buf) + goto out; + memcpy(buf, data, length); + } + + err = usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + DM_WRITE_REGS, + USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE, + 0, reg, buf, length, USB_CTRL_SET_TIMEOUT); + kfree(buf); + if (err >= 0 && err < length) + err = -EINVAL; + out: + return err; } static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value) -- cgit v1.2.3 From 4e891910f5fc7b94c720f587686636a88447c5e4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 8 Jul 2008 19:35:13 +0100 Subject: [netdrvr] wd: fix build breakage with new NS8390p API From: Alan Cox Signed-off-by: Jeff Garzik --- drivers/net/wd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wd.c b/drivers/net/wd.c index fa14255282a..6f9aa164374 100644 --- a/drivers/net/wd.c +++ b/drivers/net/wd.c @@ -337,7 +337,7 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = ei_poll; #endif - NS8390_init(dev, 0); + NS8390p_init(dev, 0); #if 1 /* Enable interrupt generation on softconfig cards -- M.U */ -- cgit v1.2.3 From 414c70cb91c445ec813b61e16fe4882807e40240 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 30 Apr 2008 15:59:04 +0100 Subject: regulator: regulator framework core This adds the regulator framework core. This framework is designed to provide a generic interface to voltage and current regulators within the Linux kernel. It's intended to provide voltage and current control to client or consumer drivers and also provide status information to user space applications through a sysfs interface. The intention is to allow systems to dynamically control regulator output in order to save power and prolong battery life. This applies to both voltage regulators (where voltage output is controllable) and current sinks (where current output is controllable). This framework safely compiles out if not selected so that client drivers can still be used in systems with no software controllable regulators. Signed-off-by: Liam Girdwood Signed-off-by: Greg Kroah-Hartman Signed-off-by: Mark Brown --- drivers/regulator/core.c | 1903 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1903 insertions(+) create mode 100644 drivers/regulator/core.c (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c new file mode 100644 index 00000000000..9c798626156 --- /dev/null +++ b/drivers/regulator/core.c @@ -0,0 +1,1903 @@ +/* + * core.c -- Voltage/Current Regulator framework. + * + * Copyright 2007, 2008 Wolfson Microelectronics PLC. + * + * Author: Liam Girdwood + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REGULATOR_VERSION "0.5" + +static DEFINE_MUTEX(regulator_list_mutex); +static LIST_HEAD(regulator_list); +static LIST_HEAD(regulator_map_list); + +/** + * struct regulator_dev + * + * Voltage / Current regulator class device. One for each regulator. + */ +struct regulator_dev { + struct regulator_desc *desc; + int use_count; + + /* lists we belong to */ + struct list_head list; /* list of all regulators */ + struct list_head slist; /* list of supplied regulators */ + + /* lists we own */ + struct list_head consumer_list; /* consumers we supply */ + struct list_head supply_list; /* regulators we supply */ + + struct blocking_notifier_head notifier; + struct mutex mutex; /* consumer lock */ + struct module *owner; + struct device dev; + struct regulation_constraints *constraints; + struct regulator_dev *supply; /* for tree */ + + void *reg_data; /* regulator_dev data */ +}; + +/** + * struct regulator_map + * + * Used to provide symbolic supply names to devices. + */ +struct regulator_map { + struct list_head list; + struct device *dev; + const char *supply; + const char *regulator; +}; + +static inline struct regulator_dev *to_rdev(struct device *d) +{ + return container_of(d, struct regulator_dev, dev); +} + +/* + * struct regulator + * + * One for each consumer device. + */ +struct regulator { + struct device *dev; + struct list_head list; + int uA_load; + int min_uV; + int max_uV; + int enabled; /* client has called enabled */ + char *supply_name; + struct device_attribute dev_attr; + struct regulator_dev *rdev; +}; + +static int _regulator_is_enabled(struct regulator_dev *rdev); +static int _regulator_disable(struct regulator_dev *rdev); +static int _regulator_get_voltage(struct regulator_dev *rdev); +static int _regulator_get_current_limit(struct regulator_dev *rdev); +static unsigned int _regulator_get_mode(struct regulator_dev *rdev); +static void _notifier_call_chain(struct regulator_dev *rdev, + unsigned long event, void *data); + +/* gets the regulator for a given consumer device */ +static struct regulator *get_device_regulator(struct device *dev) +{ + struct regulator *regulator = NULL; + struct regulator_dev *rdev; + + mutex_lock(®ulator_list_mutex); + list_for_each_entry(rdev, ®ulator_list, list) { + mutex_lock(&rdev->mutex); + list_for_each_entry(regulator, &rdev->consumer_list, list) { + if (regulator->dev == dev) { + mutex_unlock(&rdev->mutex); + mutex_unlock(®ulator_list_mutex); + return regulator; + } + } + mutex_unlock(&rdev->mutex); + } + mutex_unlock(®ulator_list_mutex); + return NULL; +} + +/* Platform voltage constraint check */ +static int regulator_check_voltage(struct regulator_dev *rdev, + int *min_uV, int *max_uV) +{ + BUG_ON(*min_uV > *max_uV); + + if (!rdev->constraints) { + printk(KERN_ERR "%s: no constraints for %s\n", __func__, + rdev->desc->name); + return -ENODEV; + } + if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { + printk(KERN_ERR "%s: operation not allowed for %s\n", + __func__, rdev->desc->name); + return -EPERM; + } + + if (*max_uV > rdev->constraints->max_uV) + *max_uV = rdev->constraints->max_uV; + if (*min_uV < rdev->constraints->min_uV) + *min_uV = rdev->constraints->min_uV; + + if (*min_uV > *max_uV) + return -EINVAL; + + return 0; +} + +/* current constraint check */ +static int regulator_check_current_limit(struct regulator_dev *rdev, + int *min_uA, int *max_uA) +{ + BUG_ON(*min_uA > *max_uA); + + if (!rdev->constraints) { + printk(KERN_ERR "%s: no constraints for %s\n", __func__, + rdev->desc->name); + return -ENODEV; + } + if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) { + printk(KERN_ERR "%s: operation not allowed for %s\n", + __func__, rdev->desc->name); + return -EPERM; + } + + if (*max_uA > rdev->constraints->max_uA) + *max_uA = rdev->constraints->max_uA; + if (*min_uA < rdev->constraints->min_uA) + *min_uA = rdev->constraints->min_uA; + + if (*min_uA > *max_uA) + return -EINVAL; + + return 0; +} + +/* operating mode constraint check */ +static int regulator_check_mode(struct regulator_dev *rdev, int mode) +{ + if (!rdev->constraints) { + printk(KERN_ERR "%s: no constraints for %s\n", __func__, + rdev->desc->name); + return -ENODEV; + } + if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) { + printk(KERN_ERR "%s: operation not allowed for %s\n", + __func__, rdev->desc->name); + return -EPERM; + } + if (!(rdev->constraints->valid_modes_mask & mode)) { + printk(KERN_ERR "%s: invalid mode %x for %s\n", + __func__, mode, rdev->desc->name); + return -EINVAL; + } + return 0; +} + +/* dynamic regulator mode switching constraint check */ +static int regulator_check_drms(struct regulator_dev *rdev) +{ + if (!rdev->constraints) { + printk(KERN_ERR "%s: no constraints for %s\n", __func__, + rdev->desc->name); + return -ENODEV; + } + if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) { + printk(KERN_ERR "%s: operation not allowed for %s\n", + __func__, rdev->desc->name); + return -EPERM; + } + return 0; +} + +static ssize_t device_requested_uA_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator *regulator; + + regulator = get_device_regulator(dev); + if (regulator == NULL) + return 0; + + return sprintf(buf, "%d\n", regulator->uA_load); +} + +static ssize_t regulator_uV_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + ssize_t ret; + + mutex_lock(&rdev->mutex); + ret = sprintf(buf, "%d\n", _regulator_get_voltage(rdev)); + mutex_unlock(&rdev->mutex); + + return ret; +} + +static ssize_t regulator_uA_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + + return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev)); +} + +static ssize_t regulator_opmode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + int mode = _regulator_get_mode(rdev); + + switch (mode) { + case REGULATOR_MODE_FAST: + return sprintf(buf, "fast\n"); + case REGULATOR_MODE_NORMAL: + return sprintf(buf, "normal\n"); + case REGULATOR_MODE_IDLE: + return sprintf(buf, "idle\n"); + case REGULATOR_MODE_STANDBY: + return sprintf(buf, "standby\n"); + } + return sprintf(buf, "unknown\n"); +} + +static ssize_t regulator_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + int state = _regulator_is_enabled(rdev); + + if (state > 0) + return sprintf(buf, "enabled\n"); + else if (state == 0) + return sprintf(buf, "disabled\n"); + else + return sprintf(buf, "unknown\n"); +} + +static ssize_t regulator_min_uA_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + + if (!rdev->constraints) + return sprintf(buf, "constraint not defined\n"); + + return sprintf(buf, "%d\n", rdev->constraints->min_uA); +} + +static ssize_t regulator_max_uA_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + + if (!rdev->constraints) + return sprintf(buf, "constraint not defined\n"); + + return sprintf(buf, "%d\n", rdev->constraints->max_uA); +} + +static ssize_t regulator_min_uV_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + + if (!rdev->constraints) + return sprintf(buf, "constraint not defined\n"); + + return sprintf(buf, "%d\n", rdev->constraints->min_uV); +} + +static ssize_t regulator_max_uV_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + + if (!rdev->constraints) + return sprintf(buf, "constraint not defined\n"); + + return sprintf(buf, "%d\n", rdev->constraints->max_uV); +} + +static ssize_t regulator_total_uA_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + struct regulator *regulator; + int uA = 0; + + mutex_lock(&rdev->mutex); + list_for_each_entry(regulator, &rdev->consumer_list, list) + uA += regulator->uA_load; + mutex_unlock(&rdev->mutex); + return sprintf(buf, "%d\n", uA); +} + +static ssize_t regulator_num_users_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + return sprintf(buf, "%d\n", rdev->use_count); +} + +static ssize_t regulator_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + + switch (rdev->desc->type) { + case REGULATOR_VOLTAGE: + return sprintf(buf, "voltage\n"); + case REGULATOR_CURRENT: + return sprintf(buf, "current\n"); + } + return sprintf(buf, "unknown\n"); +} + +static ssize_t regulator_suspend_mem_uV_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + + if (!rdev->constraints) + return sprintf(buf, "not defined\n"); + return sprintf(buf, "%d\n", rdev->constraints->state_mem.uV); +} + +static ssize_t regulator_suspend_disk_uV_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + + if (!rdev->constraints) + return sprintf(buf, "not defined\n"); + return sprintf(buf, "%d\n", rdev->constraints->state_disk.uV); +} + +static ssize_t regulator_suspend_standby_uV_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + + if (!rdev->constraints) + return sprintf(buf, "not defined\n"); + return sprintf(buf, "%d\n", rdev->constraints->state_standby.uV); +} + +static ssize_t suspend_opmode_show(struct regulator_dev *rdev, + unsigned int mode, char *buf) +{ + switch (mode) { + case REGULATOR_MODE_FAST: + return sprintf(buf, "fast\n"); + case REGULATOR_MODE_NORMAL: + return sprintf(buf, "normal\n"); + case REGULATOR_MODE_IDLE: + return sprintf(buf, "idle\n"); + case REGULATOR_MODE_STANDBY: + return sprintf(buf, "standby\n"); + } + return sprintf(buf, "unknown\n"); +} + +static ssize_t regulator_suspend_mem_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + + if (!rdev->constraints) + return sprintf(buf, "not defined\n"); + return suspend_opmode_show(rdev, + rdev->constraints->state_mem.mode, buf); +} + +static ssize_t regulator_suspend_disk_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + + if (!rdev->constraints) + return sprintf(buf, "not defined\n"); + return suspend_opmode_show(rdev, + rdev->constraints->state_disk.mode, buf); +} + +static ssize_t regulator_suspend_standby_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + + if (!rdev->constraints) + return sprintf(buf, "not defined\n"); + return suspend_opmode_show(rdev, + rdev->constraints->state_standby.mode, buf); +} + +static ssize_t regulator_suspend_mem_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + + if (!rdev->constraints) + return sprintf(buf, "not defined\n"); + + if (rdev->constraints->state_mem.enabled) + return sprintf(buf, "enabled\n"); + else + return sprintf(buf, "disabled\n"); +} + +static ssize_t regulator_suspend_disk_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + + if (!rdev->constraints) + return sprintf(buf, "not defined\n"); + + if (rdev->constraints->state_disk.enabled) + return sprintf(buf, "enabled\n"); + else + return sprintf(buf, "disabled\n"); +} + +static ssize_t regulator_suspend_standby_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = to_rdev(dev); + + if (!rdev->constraints) + return sprintf(buf, "not defined\n"); + + if (rdev->constraints->state_standby.enabled) + return sprintf(buf, "enabled\n"); + else + return sprintf(buf, "disabled\n"); +} +static struct device_attribute regulator_dev_attrs[] = { + __ATTR(microvolts, 0444, regulator_uV_show, NULL), + __ATTR(microamps, 0444, regulator_uA_show, NULL), + __ATTR(opmode, 0444, regulator_opmode_show, NULL), + __ATTR(state, 0444, regulator_state_show, NULL), + __ATTR(min_microvolts, 0444, regulator_min_uV_show, NULL), + __ATTR(min_microamps, 0444, regulator_min_uA_show, NULL), + __ATTR(max_microvolts, 0444, regulator_max_uV_show, NULL), + __ATTR(max_microamps, 0444, regulator_max_uA_show, NULL), + __ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL), + __ATTR(num_users, 0444, regulator_num_users_show, NULL), + __ATTR(type, 0444, regulator_type_show, NULL), + __ATTR(suspend_mem_microvolts, 0444, + regulator_suspend_mem_uV_show, NULL), + __ATTR(suspend_disk_microvolts, 0444, + regulator_suspend_disk_uV_show, NULL), + __ATTR(suspend_standby_microvolts, 0444, + regulator_suspend_standby_uV_show, NULL), + __ATTR(suspend_mem_mode, 0444, + regulator_suspend_mem_mode_show, NULL), + __ATTR(suspend_disk_mode, 0444, + regulator_suspend_disk_mode_show, NULL), + __ATTR(suspend_standby_mode, 0444, + regulator_suspend_standby_mode_show, NULL), + __ATTR(suspend_mem_state, 0444, + regulator_suspend_mem_state_show, NULL), + __ATTR(suspend_disk_state, 0444, + regulator_suspend_disk_state_show, NULL), + __ATTR(suspend_standby_state, 0444, + regulator_suspend_standby_state_show, NULL), + __ATTR_NULL, +}; + +static void regulator_dev_release(struct device *dev) +{ + struct regulator_dev *rdev = to_rdev(dev); + kfree(rdev); +} + +static struct class regulator_class = { + .name = "regulator", + .dev_release = regulator_dev_release, + .dev_attrs = regulator_dev_attrs, +}; + +/* Calculate the new optimum regulator operating mode based on the new total + * consumer load. All locks held by caller */ +static void drms_uA_update(struct regulator_dev *rdev) +{ + struct regulator *sibling; + int current_uA = 0, output_uV, input_uV, err; + unsigned int mode; + + err = regulator_check_drms(rdev); + if (err < 0 || !rdev->desc->ops->get_optimum_mode || + !rdev->desc->ops->get_voltage || !rdev->desc->ops->set_mode); + return; + + /* get output voltage */ + output_uV = rdev->desc->ops->get_voltage(rdev); + if (output_uV <= 0) + return; + + /* get input voltage */ + if (rdev->supply && rdev->supply->desc->ops->get_voltage) + input_uV = rdev->supply->desc->ops->get_voltage(rdev->supply); + else + input_uV = rdev->constraints->input_uV; + if (input_uV <= 0) + return; + + /* calc total requested load */ + list_for_each_entry(sibling, &rdev->consumer_list, list) + current_uA += sibling->uA_load; + + /* now get the optimum mode for our new total regulator load */ + mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV, + output_uV, current_uA); + + /* check the new mode is allowed */ + err = regulator_check_mode(rdev, mode); + if (err == 0) + rdev->desc->ops->set_mode(rdev, mode); +} + +static int suspend_set_state(struct regulator_dev *rdev, + struct regulator_state *rstate) +{ + int ret = 0; + + /* enable & disable are mandatory for suspend control */ + if (!rdev->desc->ops->set_suspend_enable || + !rdev->desc->ops->set_suspend_disable) + return -EINVAL; + + if (rstate->enabled) + ret = rdev->desc->ops->set_suspend_enable(rdev); + else + ret = rdev->desc->ops->set_suspend_disable(rdev); + if (ret < 0) { + printk(KERN_ERR "%s: failed to enabled/disable\n", __func__); + return ret; + } + + if (rdev->desc->ops->set_suspend_voltage && rstate->uV > 0) { + ret = rdev->desc->ops->set_suspend_voltage(rdev, rstate->uV); + if (ret < 0) { + printk(KERN_ERR "%s: failed to set voltage\n", + __func__); + return ret; + } + } + + if (rdev->desc->ops->set_suspend_mode && rstate->mode > 0) { + ret = rdev->desc->ops->set_suspend_mode(rdev, rstate->mode); + if (ret < 0) { + printk(KERN_ERR "%s: failed to set mode\n", __func__); + return ret; + } + } + return ret; +} + +/* locks held by caller */ +static int suspend_prepare(struct regulator_dev *rdev, suspend_state_t state) +{ + if (!rdev->constraints) + return -EINVAL; + + switch (state) { + case PM_SUSPEND_STANDBY: + return suspend_set_state(rdev, + &rdev->constraints->state_standby); + case PM_SUSPEND_MEM: + return suspend_set_state(rdev, + &rdev->constraints->state_mem); + case PM_SUSPEND_MAX: + return suspend_set_state(rdev, + &rdev->constraints->state_disk); + default: + return -EINVAL; + } +} + +static void print_constraints(struct regulator_dev *rdev) +{ + struct regulation_constraints *constraints = rdev->constraints; + char buf[80]; + int count; + + if (rdev->desc->type == REGULATOR_VOLTAGE) { + if (constraints->min_uV == constraints->max_uV) + count = sprintf(buf, "%d mV ", + constraints->min_uV / 1000); + else + count = sprintf(buf, "%d <--> %d mV ", + constraints->min_uV / 1000, + constraints->max_uV / 1000); + } else { + if (constraints->min_uA == constraints->max_uA) + count = sprintf(buf, "%d mA ", + constraints->min_uA / 1000); + else + count = sprintf(buf, "%d <--> %d mA ", + constraints->min_uA / 1000, + constraints->max_uA / 1000); + } + if (constraints->valid_modes_mask & REGULATOR_MODE_FAST) + count += sprintf(buf + count, "fast "); + if (constraints->valid_modes_mask & REGULATOR_MODE_NORMAL) + count += sprintf(buf + count, "normal "); + if (constraints->valid_modes_mask & REGULATOR_MODE_IDLE) + count += sprintf(buf + count, "idle "); + if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY) + count += sprintf(buf + count, "standby"); + + printk(KERN_INFO "regulator: %s: %s\n", rdev->desc->name, buf); +} + +#define REG_STR_SIZE 32 + +static struct regulator *create_regulator(struct regulator_dev *rdev, + struct device *dev, + const char *supply_name) +{ + struct regulator *regulator; + char buf[REG_STR_SIZE]; + int err, size; + + regulator = kzalloc(sizeof(*regulator), GFP_KERNEL); + if (regulator == NULL) + return NULL; + + mutex_lock(&rdev->mutex); + regulator->rdev = rdev; + list_add(®ulator->list, &rdev->consumer_list); + + if (dev) { + /* create a 'requested_microamps_name' sysfs entry */ + size = scnprintf(buf, REG_STR_SIZE, "microamps_requested_%s", + supply_name); + if (size >= REG_STR_SIZE) + goto overflow_err; + + regulator->dev = dev; + regulator->dev_attr.attr.name = kstrdup(buf, GFP_KERNEL); + if (regulator->dev_attr.attr.name == NULL) + goto attr_name_err; + + regulator->dev_attr.attr.owner = THIS_MODULE; + regulator->dev_attr.attr.mode = 0444; + regulator->dev_attr.show = device_requested_uA_show; + err = device_create_file(dev, ®ulator->dev_attr); + if (err < 0) { + printk(KERN_WARNING "%s: could not add regulator_dev" + " load sysfs\n", __func__); + goto attr_name_err; + } + + /* also add a link to the device sysfs entry */ + size = scnprintf(buf, REG_STR_SIZE, "%s-%s", + dev->kobj.name, supply_name); + if (size >= REG_STR_SIZE) + goto attr_err; + + regulator->supply_name = kstrdup(buf, GFP_KERNEL); + if (regulator->supply_name == NULL) + goto attr_err; + + err = sysfs_create_link(&rdev->dev.kobj, &dev->kobj, + buf); + if (err) { + printk(KERN_WARNING + "%s: could not add device link %s err %d\n", + __func__, dev->kobj.name, err); + device_remove_file(dev, ®ulator->dev_attr); + goto link_name_err; + } + } + mutex_unlock(&rdev->mutex); + return regulator; +link_name_err: + kfree(regulator->supply_name); +attr_err: + device_remove_file(regulator->dev, ®ulator->dev_attr); +attr_name_err: + kfree(regulator->dev_attr.attr.name); +overflow_err: + list_del(®ulator->list); + kfree(regulator); + mutex_unlock(&rdev->mutex); + return NULL; +} + +/** + * regulator_get - lookup and obtain a reference to a regulator. + * @dev: device for regulator "consumer" + * @id: Supply name or regulator ID. + * + * Returns a struct regulator corresponding to the regulator producer, + * or IS_ERR() condition containing errno. Use of supply names + * configured via regulator_set_device_supply() is strongly + * encouraged. + */ +struct regulator *regulator_get(struct device *dev, const char *id) +{ + struct regulator_dev *rdev; + struct regulator_map *map; + struct regulator *regulator = ERR_PTR(-ENODEV); + const char *supply = id; + + if (id == NULL) { + printk(KERN_ERR "regulator: get() with no identifier\n"); + return regulator; + } + + mutex_lock(®ulator_list_mutex); + + list_for_each_entry(map, ®ulator_map_list, list) { + if (dev == map->dev && + strcmp(map->supply, id) == 0) { + supply = map->regulator; + break; + } + } + + list_for_each_entry(rdev, ®ulator_list, list) { + if (strcmp(supply, rdev->desc->name) == 0 && + try_module_get(rdev->owner)) + goto found; + } + printk(KERN_ERR "regulator: Unable to get requested regulator: %s\n", + id); + mutex_unlock(®ulator_list_mutex); + return regulator; + +found: + regulator = create_regulator(rdev, dev, id); + if (regulator == NULL) { + regulator = ERR_PTR(-ENOMEM); + module_put(rdev->owner); + } + + mutex_unlock(®ulator_list_mutex); + return regulator; +} +EXPORT_SYMBOL_GPL(regulator_get); + +/** + * regulator_put - "free" the regulator source + * @regulator: regulator source + * + * Note: drivers must ensure that all regulator_enable calls made on this + * regulator source are balanced by regulator_disable calls prior to calling + * this function. + */ +void regulator_put(struct regulator *regulator) +{ + struct regulator_dev *rdev; + + if (regulator == NULL || IS_ERR(regulator)) + return; + + if (regulator->enabled) { + printk(KERN_WARNING "Releasing supply %s while enabled\n", + regulator->supply_name); + WARN_ON(regulator->enabled); + regulator_disable(regulator); + } + + mutex_lock(®ulator_list_mutex); + rdev = regulator->rdev; + + /* remove any sysfs entries */ + if (regulator->dev) { + sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); + kfree(regulator->supply_name); + device_remove_file(regulator->dev, ®ulator->dev_attr); + kfree(regulator->dev_attr.attr.name); + } + list_del(®ulator->list); + kfree(regulator); + + module_put(rdev->owner); + mutex_unlock(®ulator_list_mutex); +} +EXPORT_SYMBOL_GPL(regulator_put); + +/* locks held by regulator_enable() */ +static int _regulator_enable(struct regulator_dev *rdev) +{ + int ret = -EINVAL; + + if (!rdev->constraints) { + printk(KERN_ERR "%s: %s has no constraints\n", + __func__, rdev->desc->name); + return ret; + } + + /* do we need to enable the supply regulator first */ + if (rdev->supply) { + ret = _regulator_enable(rdev->supply); + if (ret < 0) { + printk(KERN_ERR "%s: failed to enable %s: %d\n", + __func__, rdev->desc->name, ret); + return ret; + } + } + + /* check voltage and requested load before enabling */ + if (rdev->desc->ops->enable) { + + if (rdev->constraints && + (rdev->constraints->valid_ops_mask & + REGULATOR_CHANGE_DRMS)) + drms_uA_update(rdev); + + ret = rdev->desc->ops->enable(rdev); + if (ret < 0) { + printk(KERN_ERR "%s: failed to enable %s: %d\n", + __func__, rdev->desc->name, ret); + return ret; + } + rdev->use_count++; + return ret; + } + + return ret; +} + +/** + * regulator_enable - enable regulator output + * @regulator: regulator source + * + * Enable the regulator output at the predefined voltage or current value. + * NOTE: the output value can be set by other drivers, boot loader or may be + * hardwired in the regulator. + * NOTE: calls to regulator_enable() must be balanced with calls to + * regulator_disable(). + */ +int regulator_enable(struct regulator *regulator) +{ + int ret; + + if (regulator->enabled) { + printk(KERN_CRIT "Regulator %s already enabled\n", + regulator->supply_name); + WARN_ON(regulator->enabled); + return 0; + } + + mutex_lock(®ulator->rdev->mutex); + regulator->enabled = 1; + ret = _regulator_enable(regulator->rdev); + if (ret != 0) + regulator->enabled = 0; + mutex_unlock(®ulator->rdev->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(regulator_enable); + +/* locks held by regulator_disable() */ +static int _regulator_disable(struct regulator_dev *rdev) +{ + int ret = 0; + + /* are we the last user and permitted to disable ? */ + if (rdev->use_count == 1 && !rdev->constraints->always_on) { + + /* we are last user */ + if (rdev->desc->ops->disable) { + ret = rdev->desc->ops->disable(rdev); + if (ret < 0) { + printk(KERN_ERR "%s: failed to disable %s\n", + __func__, rdev->desc->name); + return ret; + } + } + + /* decrease our supplies ref count and disable if required */ + if (rdev->supply) + _regulator_disable(rdev->supply); + + rdev->use_count = 0; + } else if (rdev->use_count > 1) { + + if (rdev->constraints && + (rdev->constraints->valid_ops_mask & + REGULATOR_CHANGE_DRMS)) + drms_uA_update(rdev); + + rdev->use_count--; + } + return ret; +} + +/** + * regulator_disable - disable regulator output + * @regulator: regulator source + * + * Disable the regulator output voltage or current. + * NOTE: this will only disable the regulator output if no other consumer + * devices have it enabled. + * NOTE: calls to regulator_enable() must be balanced with calls to + * regulator_disable(). + */ +int regulator_disable(struct regulator *regulator) +{ + int ret; + + if (!regulator->enabled) { + printk(KERN_ERR "%s: not in use by this consumer\n", + __func__); + return 0; + } + + mutex_lock(®ulator->rdev->mutex); + regulator->enabled = 0; + regulator->uA_load = 0; + ret = _regulator_disable(regulator->rdev); + mutex_unlock(®ulator->rdev->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(regulator_disable); + +/* locks held by regulator_force_disable() */ +static int _regulator_force_disable(struct regulator_dev *rdev) +{ + int ret = 0; + + /* force disable */ + if (rdev->desc->ops->disable) { + /* ah well, who wants to live forever... */ + ret = rdev->desc->ops->disable(rdev); + if (ret < 0) { + printk(KERN_ERR "%s: failed to force disable %s\n", + __func__, rdev->desc->name); + return ret; + } + /* notify other consumers that power has been forced off */ + _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE, + NULL); + } + + /* decrease our supplies ref count and disable if required */ + if (rdev->supply) + _regulator_disable(rdev->supply); + + rdev->use_count = 0; + return ret; +} + +/** + * regulator_force_disable - force disable regulator output + * @regulator: regulator source + * + * Forcibly disable the regulator output voltage or current. + * NOTE: this *will* disable the regulator output even if other consumer + * devices have it enabled. This should be used for situations when device + * damage will likely occur if the regulator is not disabled (e.g. over temp). + */ +int regulator_force_disable(struct regulator *regulator) +{ + int ret; + + mutex_lock(®ulator->rdev->mutex); + regulator->enabled = 0; + regulator->uA_load = 0; + ret = _regulator_force_disable(regulator->rdev); + mutex_unlock(®ulator->rdev->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(regulator_force_disable); + +static int _regulator_is_enabled(struct regulator_dev *rdev) +{ + int ret; + + mutex_lock(&rdev->mutex); + + /* sanity check */ + if (!rdev->desc->ops->is_enabled) { + ret = -EINVAL; + goto out; + } + + ret = rdev->desc->ops->is_enabled(rdev); +out: + mutex_unlock(&rdev->mutex); + return ret; +} + +/** + * regulator_is_enabled - is the regulator output enabled + * @regulator: regulator source + * + * Returns zero for disabled otherwise return number of enable requests. + */ +int regulator_is_enabled(struct regulator *regulator) +{ + return _regulator_is_enabled(regulator->rdev); +} +EXPORT_SYMBOL_GPL(regulator_is_enabled); + +/** + * regulator_set_voltage - set regulator output voltage + * @regulator: regulator source + * @min_uV: Minimum required voltage in uV + * @max_uV: Maximum acceptable voltage in uV + * + * Sets a voltage regulator to the desired output voltage. This can be set + * during any regulator state. IOW, regulator can be disabled or enabled. + * + * If the regulator is enabled then the voltage will change to the new value + * immediately otherwise if the regulator is disabled the regulator will + * output at the new voltage when enabled. + * + * NOTE: If the regulator is shared between several devices then the lowest + * request voltage that meets the system constraints will be used. + * NOTE: Regulator system constraints must be set for this regulator before + * calling this function otherwise this call will fail. + */ +int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) +{ + struct regulator_dev *rdev = regulator->rdev; + int ret; + + mutex_lock(&rdev->mutex); + + /* sanity check */ + if (!rdev->desc->ops->set_voltage) { + ret = -EINVAL; + goto out; + } + + /* constraints check */ + ret = regulator_check_voltage(rdev, &min_uV, &max_uV); + if (ret < 0) + goto out; + regulator->min_uV = min_uV; + regulator->max_uV = max_uV; + ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV); + +out: + mutex_unlock(&rdev->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(regulator_set_voltage); + +static int _regulator_get_voltage(struct regulator_dev *rdev) +{ + /* sanity check */ + if (rdev->desc->ops->get_voltage) + return rdev->desc->ops->get_voltage(rdev); + else + return -EINVAL; +} + +/** + * regulator_get_voltage - get regulator output voltage + * @regulator: regulator source + * + * This returns the current regulator voltage in uV. + * + * NOTE: If the regulator is disabled it will return the voltage value. This + * function should not be used to determine regulator state. + */ +int regulator_get_voltage(struct regulator *regulator) +{ + int ret; + + mutex_lock(®ulator->rdev->mutex); + + ret = _regulator_get_voltage(regulator->rdev); + + mutex_unlock(®ulator->rdev->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(regulator_get_voltage); + +/** + * regulator_set_current_limit - set regulator output current limit + * @regulator: regulator source + * @min_uA: Minimuum supported current in uA + * @max_uA: Maximum supported current in uA + * + * Sets current sink to the desired output current. This can be set during + * any regulator state. IOW, regulator can be disabled or enabled. + * + * If the regulator is enabled then the current will change to the new value + * immediately otherwise if the regulator is disabled the regulator will + * output at the new current when enabled. + * + * NOTE: Regulator system constraints must be set for this regulator before + * calling this function otherwise this call will fail. + */ +int regulator_set_current_limit(struct regulator *regulator, + int min_uA, int max_uA) +{ + struct regulator_dev *rdev = regulator->rdev; + int ret; + + mutex_lock(&rdev->mutex); + + /* sanity check */ + if (!rdev->desc->ops->set_current_limit) { + ret = -EINVAL; + goto out; + } + + /* constraints check */ + ret = regulator_check_current_limit(rdev, &min_uA, &max_uA); + if (ret < 0) + goto out; + + ret = rdev->desc->ops->set_current_limit(rdev, min_uA, max_uA); +out: + mutex_unlock(&rdev->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(regulator_set_current_limit); + +static int _regulator_get_current_limit(struct regulator_dev *rdev) +{ + int ret; + + mutex_lock(&rdev->mutex); + + /* sanity check */ + if (!rdev->desc->ops->get_current_limit) { + ret = -EINVAL; + goto out; + } + + ret = rdev->desc->ops->get_current_limit(rdev); +out: + mutex_unlock(&rdev->mutex); + return ret; +} + +/** + * regulator_get_current_limit - get regulator output current + * @regulator: regulator source + * + * This returns the current supplied by the specified current sink in uA. + * + * NOTE: If the regulator is disabled it will return the current value. This + * function should not be used to determine regulator state. + */ +int regulator_get_current_limit(struct regulator *regulator) +{ + return _regulator_get_current_limit(regulator->rdev); +} +EXPORT_SYMBOL_GPL(regulator_get_current_limit); + +/** + * regulator_set_mode - set regulator operating mode + * @regulator: regulator source + * @mode: operating mode - one of the REGULATOR_MODE constants + * + * Set regulator operating mode to increase regulator efficiency or improve + * regulation performance. + * + * NOTE: Regulator system constraints must be set for this regulator before + * calling this function otherwise this call will fail. + */ +int regulator_set_mode(struct regulator *regulator, unsigned int mode) +{ + struct regulator_dev *rdev = regulator->rdev; + int ret; + + mutex_lock(&rdev->mutex); + + /* sanity check */ + if (!rdev->desc->ops->set_mode) { + ret = -EINVAL; + goto out; + } + + /* constraints check */ + ret = regulator_check_mode(rdev, mode); + if (ret < 0) + goto out; + + ret = rdev->desc->ops->set_mode(rdev, mode); +out: + mutex_unlock(&rdev->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(regulator_set_mode); + +static unsigned int _regulator_get_mode(struct regulator_dev *rdev) +{ + int ret; + + mutex_lock(&rdev->mutex); + + /* sanity check */ + if (!rdev->desc->ops->get_mode) { + ret = -EINVAL; + goto out; + } + + ret = rdev->desc->ops->get_mode(rdev); +out: + mutex_unlock(&rdev->mutex); + return ret; +} + +/** + * regulator_get_mode - get regulator operating mode + * @regulator: regulator source + * + * Get the current regulator operating mode. + */ +unsigned int regulator_get_mode(struct regulator *regulator) +{ + return _regulator_get_mode(regulator->rdev); +} +EXPORT_SYMBOL_GPL(regulator_get_mode); + +/** + * regulator_set_optimum_mode - set regulator optimum operating mode + * @regulator: regulator source + * @uA_load: load current + * + * Notifies the regulator core of a new device load. This is then used by + * DRMS (if enabled by constraints) to set the most efficient regulator + * operating mode for the new regulator loading. + * + * Consumer devices notify their supply regulator of the maximum power + * they will require (can be taken from device datasheet in the power + * consumption tables) when they change operational status and hence power + * state. Examples of operational state changes that can affect power + * consumption are :- + * + * o Device is opened / closed. + * o Device I/O is about to begin or has just finished. + * o Device is idling in between work. + * + * This information is also exported via sysfs to userspace. + * + * DRMS will sum the total requested load on the regulator and change + * to the most efficient operating mode if platform constraints allow. + * + * Returns the new regulator mode or error. + */ +int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) +{ + struct regulator_dev *rdev = regulator->rdev; + struct regulator *consumer; + int ret, output_uV, input_uV, total_uA_load = 0; + unsigned int mode; + + mutex_lock(&rdev->mutex); + + regulator->uA_load = uA_load; + ret = regulator_check_drms(rdev); + if (ret < 0) + goto out; + ret = -EINVAL; + + /* sanity check */ + if (!rdev->desc->ops->get_optimum_mode) + goto out; + + /* get output voltage */ + output_uV = rdev->desc->ops->get_voltage(rdev); + if (output_uV <= 0) { + printk(KERN_ERR "%s: invalid output voltage found for %s\n", + __func__, rdev->desc->name); + goto out; + } + + /* get input voltage */ + if (rdev->supply && rdev->supply->desc->ops->get_voltage) + input_uV = rdev->supply->desc->ops->get_voltage(rdev->supply); + else + input_uV = rdev->constraints->input_uV; + if (input_uV <= 0) { + printk(KERN_ERR "%s: invalid input voltage found for %s\n", + __func__, rdev->desc->name); + goto out; + } + + /* calc total requested load for this regulator */ + list_for_each_entry(consumer, &rdev->consumer_list, list) + total_uA_load += consumer->uA_load; + + mode = rdev->desc->ops->get_optimum_mode(rdev, + input_uV, output_uV, + total_uA_load); + if (ret <= 0) { + printk(KERN_ERR "%s: failed to get optimum mode for %s @" + " %d uA %d -> %d uV\n", __func__, rdev->desc->name, + total_uA_load, input_uV, output_uV); + goto out; + } + + ret = rdev->desc->ops->set_mode(rdev, mode); + if (ret <= 0) { + printk(KERN_ERR "%s: failed to set optimum mode %x for %s\n", + __func__, mode, rdev->desc->name); + goto out; + } + ret = mode; +out: + mutex_unlock(&rdev->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(regulator_set_optimum_mode); + +/** + * regulator_register_notifier - register regulator event notifier + * @regulator: regulator source + * @notifier_block: notifier block + * + * Register notifier block to receive regulator events. + */ +int regulator_register_notifier(struct regulator *regulator, + struct notifier_block *nb) +{ + return blocking_notifier_chain_register(®ulator->rdev->notifier, + nb); +} +EXPORT_SYMBOL_GPL(regulator_register_notifier); + +/** + * regulator_unregister_notifier - unregister regulator event notifier + * @regulator: regulator source + * @notifier_block: notifier block + * + * Unregister regulator event notifier block. + */ +int regulator_unregister_notifier(struct regulator *regulator, + struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(®ulator->rdev->notifier, + nb); +} +EXPORT_SYMBOL_GPL(regulator_unregister_notifier); + +/* notify regulator consumers and downstream regulator consumers */ +static void _notifier_call_chain(struct regulator_dev *rdev, + unsigned long event, void *data) +{ + struct regulator_dev *_rdev; + + /* call rdev chain first */ + mutex_lock(&rdev->mutex); + blocking_notifier_call_chain(&rdev->notifier, event, NULL); + mutex_unlock(&rdev->mutex); + + /* now notify regulator we supply */ + list_for_each_entry(_rdev, &rdev->supply_list, slist) + _notifier_call_chain(_rdev, event, data); +} + +/** + * regulator_bulk_get - get multiple regulator consumers + * + * @dev: Device to supply + * @num_consumers: Number of consumers to register + * @consumers: Configuration of consumers; clients are stored here. + * + * @return 0 on success, an errno on failure. + * + * This helper function allows drivers to get several regulator + * consumers in one operation. If any of the regulators cannot be + * acquired then any regulators that were allocated will be freed + * before returning to the caller. + */ +int regulator_bulk_get(struct device *dev, int num_consumers, + struct regulator_bulk_data *consumers) +{ + int i; + int ret; + + for (i = 0; i < num_consumers; i++) + consumers[i].consumer = NULL; + + for (i = 0; i < num_consumers; i++) { + consumers[i].consumer = regulator_get(dev, + consumers[i].supply); + if (IS_ERR(consumers[i].consumer)) { + dev_err(dev, "Failed to get supply '%s'\n", + consumers[i].supply); + ret = PTR_ERR(consumers[i].consumer); + consumers[i].consumer = NULL; + goto err; + } + } + + return 0; + +err: + for (i = 0; i < num_consumers && consumers[i].consumer; i++) + regulator_put(consumers[i].consumer); + + return ret; +} +EXPORT_SYMBOL_GPL(regulator_bulk_get); + +/** + * regulator_bulk_enable - enable multiple regulator consumers + * + * @num_consumers: Number of consumers + * @consumers: Consumer data; clients are stored here. + * @return 0 on success, an errno on failure + * + * This convenience API allows consumers to enable multiple regulator + * clients in a single API call. If any consumers cannot be enabled + * then any others that were enabled will be disabled again prior to + * return. + */ +int regulator_bulk_enable(int num_consumers, + struct regulator_bulk_data *consumers) +{ + int i; + int ret; + + for (i = 0; i < num_consumers; i++) { + ret = regulator_enable(consumers[i].consumer); + if (ret != 0) + goto err; + } + + return 0; + +err: + printk(KERN_ERR "Failed to enable %s\n", consumers[i].supply); + for (i = 0; i < num_consumers; i++) + regulator_disable(consumers[i].consumer); + + return ret; +} +EXPORT_SYMBOL_GPL(regulator_bulk_enable); + +/** + * regulator_bulk_disable - disable multiple regulator consumers + * + * @num_consumers: Number of consumers + * @consumers: Consumer data; clients are stored here. + * @return 0 on success, an errno on failure + * + * This convenience API allows consumers to disable multiple regulator + * clients in a single API call. If any consumers cannot be enabled + * then any others that were disabled will be disabled again prior to + * return. + */ +int regulator_bulk_disable(int num_consumers, + struct regulator_bulk_data *consumers) +{ + int i; + int ret; + + for (i = 0; i < num_consumers; i++) { + ret = regulator_disable(consumers[i].consumer); + if (ret != 0) + goto err; + } + + return 0; + +err: + printk(KERN_ERR "Failed to disable %s\n", consumers[i].supply); + for (i = 0; i < num_consumers; i++) + regulator_enable(consumers[i].consumer); + + return ret; +} +EXPORT_SYMBOL_GPL(regulator_bulk_disable); + +/** + * regulator_bulk_free - free multiple regulator consumers + * + * @num_consumers: Number of consumers + * @consumers: Consumer data; clients are stored here. + * + * This convenience API allows consumers to free multiple regulator + * clients in a single API call. + */ +void regulator_bulk_free(int num_consumers, + struct regulator_bulk_data *consumers) +{ + int i; + + for (i = 0; i < num_consumers; i++) { + regulator_put(consumers[i].consumer); + consumers[i].consumer = NULL; + } +} +EXPORT_SYMBOL_GPL(regulator_bulk_free); + +/** + * regulator_notifier_call_chain - call regulator event notifier + * @regulator: regulator source + * @event: notifier block + * @data: + * + * Called by regulator drivers to notify clients a regulator event has + * occurred. We also notify regulator clients downstream. + */ +int regulator_notifier_call_chain(struct regulator_dev *rdev, + unsigned long event, void *data) +{ + _notifier_call_chain(rdev, event, data); + return NOTIFY_DONE; + +} +EXPORT_SYMBOL_GPL(regulator_notifier_call_chain); + +/** + * regulator_register - register regulator + * @regulator: regulator source + * @reg_data: private regulator data + * + * Called by regulator drivers to register a regulator. + * Returns 0 on success. + */ +struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, + void *reg_data) +{ + static atomic_t regulator_no = ATOMIC_INIT(0); + struct regulator_dev *rdev; + int ret; + + if (regulator_desc == NULL) + return ERR_PTR(-EINVAL); + + if (regulator_desc->name == NULL || regulator_desc->ops == NULL) + return ERR_PTR(-EINVAL); + + if (!regulator_desc->type == REGULATOR_VOLTAGE && + !regulator_desc->type == REGULATOR_CURRENT) + return ERR_PTR(-EINVAL); + + rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); + if (rdev == NULL) + return ERR_PTR(-ENOMEM); + + mutex_lock(®ulator_list_mutex); + + mutex_init(&rdev->mutex); + rdev->reg_data = reg_data; + rdev->owner = regulator_desc->owner; + rdev->desc = regulator_desc; + INIT_LIST_HEAD(&rdev->consumer_list); + INIT_LIST_HEAD(&rdev->supply_list); + INIT_LIST_HEAD(&rdev->list); + INIT_LIST_HEAD(&rdev->slist); + BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); + + rdev->dev.class = ®ulator_class; + device_initialize(&rdev->dev); + snprintf(rdev->dev.bus_id, sizeof(rdev->dev.bus_id), + "regulator_%ld_%s", + (unsigned long)atomic_inc_return(®ulator_no) - 1, + regulator_desc->name); + + ret = device_add(&rdev->dev); + if (ret == 0) + list_add(&rdev->list, ®ulator_list); + else { + kfree(rdev); + rdev = ERR_PTR(ret); + } + mutex_unlock(®ulator_list_mutex); + return rdev; +} +EXPORT_SYMBOL_GPL(regulator_register); + +/** + * regulator_unregister - unregister regulator + * @regulator: regulator source + * + * Called by regulator drivers to unregister a regulator. + */ +void regulator_unregister(struct regulator_dev *rdev) +{ + if (rdev == NULL) + return; + + mutex_lock(®ulator_list_mutex); + list_del(&rdev->list); + if (rdev->supply) + sysfs_remove_link(&rdev->dev.kobj, "supply"); + device_unregister(&rdev->dev); + mutex_unlock(®ulator_list_mutex); +} +EXPORT_SYMBOL_GPL(regulator_unregister); + +/** + * regulator_set_supply - set regulator supply regulator + * @regulator: regulator name + * @supply: supply regulator name + * + * Called by platform initialisation code to set the supply regulator for this + * regulator. This ensures that a regulators supply will also be enabled by the + * core if it's child is enabled. + */ +int regulator_set_supply(const char *regulator, const char *supply) +{ + struct regulator_dev *rdev, *supply_rdev; + int err; + + if (regulator == NULL || supply == NULL) + return -EINVAL; + + mutex_lock(®ulator_list_mutex); + + list_for_each_entry(rdev, ®ulator_list, list) { + if (!strcmp(rdev->desc->name, regulator)) + goto found_regulator; + } + mutex_unlock(®ulator_list_mutex); + return -ENODEV; + +found_regulator: + list_for_each_entry(supply_rdev, ®ulator_list, list) { + if (!strcmp(supply_rdev->desc->name, supply)) + goto found_supply; + } + mutex_unlock(®ulator_list_mutex); + return -ENODEV; + +found_supply: + err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj, + "supply"); + if (err) { + printk(KERN_ERR + "%s: could not add device link %s err %d\n", + __func__, supply_rdev->dev.kobj.name, err); + goto out; + } + rdev->supply = supply_rdev; + list_add(&rdev->slist, &supply_rdev->supply_list); +out: + mutex_unlock(®ulator_list_mutex); + return err; +} +EXPORT_SYMBOL_GPL(regulator_set_supply); + +/** + * regulator_get_supply - get regulator supply regulator + * @regulator: regulator name + * + * Returns the supply supply regulator name or NULL if no supply regulator + * exists (i.e the regulator is supplied directly from USB, Line, Battery, etc) + */ +const char *regulator_get_supply(const char *regulator) +{ + struct regulator_dev *rdev; + + if (regulator == NULL) + return NULL; + + mutex_lock(®ulator_list_mutex); + list_for_each_entry(rdev, ®ulator_list, list) { + if (!strcmp(rdev->desc->name, regulator)) + goto found; + } + mutex_unlock(®ulator_list_mutex); + return NULL; + +found: + mutex_unlock(®ulator_list_mutex); + if (rdev->supply) + return rdev->supply->desc->name; + else + return NULL; +} +EXPORT_SYMBOL_GPL(regulator_get_supply); + +/** + * regulator_set_machine_constraints - sets regulator constraints + * @regulator: regulator source + * + * Allows platform initialisation code to define and constrain + * regulator circuits e.g. valid voltage/current ranges, etc. NOTE: + * Constraints *must* be set by platform code in order for some + * regulator operations to proceed i.e. set_voltage, set_current_limit, + * set_mode. + */ +int regulator_set_machine_constraints(const char *regulator_name, + struct regulation_constraints *constraints) +{ + struct regulator_dev *rdev; + int ret = 0; + + if (regulator_name == NULL) + return -EINVAL; + + mutex_lock(®ulator_list_mutex); + + list_for_each_entry(rdev, ®ulator_list, list) { + if (!strcmp(regulator_name, rdev->desc->name)) + goto found; + } + ret = -ENODEV; + goto out; + +found: + mutex_lock(&rdev->mutex); + rdev->constraints = constraints; + + /* do we need to apply the constraint voltage */ + if (rdev->constraints->apply_uV && + rdev->constraints->min_uV == rdev->constraints->max_uV && + rdev->desc->ops->set_voltage) { + ret = rdev->desc->ops->set_voltage(rdev, + rdev->constraints->min_uV, rdev->constraints->max_uV); + if (ret < 0) { + printk(KERN_ERR "%s: failed to apply %duV" + " constraint\n", __func__, + rdev->constraints->min_uV); + rdev->constraints = NULL; + goto out; + } + } + + /* are we enabled at boot time by firmware / bootloader */ + if (rdev->constraints->boot_on) + rdev->use_count = 1; + + /* do we need to setup our suspend state */ + if (constraints->initial_state) + ret = suspend_prepare(rdev, constraints->initial_state); + + print_constraints(rdev); + mutex_unlock(&rdev->mutex); + +out: + mutex_unlock(®ulator_list_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(regulator_set_machine_constraints); + + +/** + * regulator_set_device_supply: Bind a regulator to a symbolic supply + * @regulator: regulator source + * @dev: device the supply applies to + * @supply: symbolic name for supply + * + * Allows platform initialisation code to map physical regulator + * sources to symbolic names for supplies for use by devices. Devices + * should use these symbolic names to request regulators, avoiding the + * need to provide board-specific regulator names as platform data. + */ +int regulator_set_device_supply(const char *regulator, struct device *dev, + const char *supply) +{ + struct regulator_map *node; + + if (regulator == NULL || supply == NULL) + return -EINVAL; + + node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL); + if (node == NULL) + return -ENOMEM; + + node->regulator = regulator; + node->dev = dev; + node->supply = supply; + + mutex_lock(®ulator_list_mutex); + list_add(&node->list, ®ulator_map_list); + mutex_unlock(®ulator_list_mutex); + return 0; +} +EXPORT_SYMBOL_GPL(regulator_set_device_supply); + +/** + * regulator_suspend_prepare: prepare regulators for system wide suspend + * @state: system suspend state + * + * Configure each regulator with it's suspend operating parameters for state. + * This will usually be called by machine suspend code prior to supending. + */ +int regulator_suspend_prepare(suspend_state_t state) +{ + struct regulator_dev *rdev; + int ret = 0; + + /* ON is handled by regulator active state */ + if (state == PM_SUSPEND_ON) + return -EINVAL; + + mutex_lock(®ulator_list_mutex); + list_for_each_entry(rdev, ®ulator_list, list) { + + mutex_lock(&rdev->mutex); + ret = suspend_prepare(rdev, state); + mutex_unlock(&rdev->mutex); + + if (ret < 0) { + printk(KERN_ERR "%s: failed to prepare %s\n", + __func__, rdev->desc->name); + goto out; + } + } +out: + mutex_unlock(®ulator_list_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(regulator_suspend_prepare); + +/** + * rdev_get_drvdata - get rdev regulator driver data + * @regulator: regulator + * + * Get rdev regulator driver private data. This call can be used in the + * regulator driver context. + */ +void *rdev_get_drvdata(struct regulator_dev *rdev) +{ + return rdev->reg_data; +} +EXPORT_SYMBOL_GPL(rdev_get_drvdata); + +/** + * regulator_get_drvdata - get regulator driver data + * @regulator: regulator + * + * Get regulator driver private data. This call can be used in the consumer + * driver context when non API regulator specific functions need to be called. + */ +void *regulator_get_drvdata(struct regulator *regulator) +{ + return regulator->rdev->reg_data; +} +EXPORT_SYMBOL_GPL(regulator_get_drvdata); + +/** + * regulator_set_drvdata - set regulator driver data + * @regulator: regulator + * @data: data + */ +void regulator_set_drvdata(struct regulator *regulator, void *data) +{ + regulator->rdev->reg_data = data; +} +EXPORT_SYMBOL_GPL(regulator_set_drvdata); + +/** + * regulator_get_id - get regulator ID + * @regulator: regulator + */ +int rdev_get_id(struct regulator_dev *rdev) +{ + return rdev->desc->id; +} +EXPORT_SYMBOL_GPL(rdev_get_id); + +static int __init regulator_init(void) +{ + printk(KERN_INFO "regulator: core version %s\n", REGULATOR_VERSION); + return class_register(®ulator_class); +} + +/* init early to allow our consumers to complete system booting */ +core_initcall(regulator_init); -- cgit v1.2.3 From 4b74ff6512492dedea353f89d9b56cb715df0d7f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 30 Apr 2008 16:27:12 +0100 Subject: regulator: add support for fixed regulators. This adds supports for regulator that are not software controlable. It allows them to coexist in systems with mixed supplies. Signed-off-by: Mark Brown Signed-off-by: Mike Rapoport Signed-off-by: Liam Girdwood --- drivers/regulator/fixed.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 drivers/regulator/fixed.c (limited to 'drivers') diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c new file mode 100644 index 00000000000..d31db3e1491 --- /dev/null +++ b/drivers/regulator/fixed.c @@ -0,0 +1,129 @@ +/* + * fixed.c + * + * Copyright 2008 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This is useful for systems with mixed controllable and + * non-controllable regulators, as well as for allowing testing on + * systems with no controllable regulators. + */ + +#include +#include +#include +#include +#include + +struct fixed_voltage_data { + struct regulator_desc desc; + struct regulator_dev *dev; + int microvolts; +}; + +static int fixed_voltage_is_enabled(struct regulator_dev *dev) +{ + return 1; +} + +static int fixed_voltage_enable(struct regulator_dev *dev) +{ + return 0; +} + +static int fixed_voltage_get_voltage(struct regulator_dev *dev) +{ + struct fixed_voltage_data *data = rdev_get_drvdata(dev); + + return data->microvolts; +} + +static struct regulator_ops fixed_voltage_ops = { + .is_enabled = fixed_voltage_is_enabled, + .enable = fixed_voltage_enable, + .get_voltage = fixed_voltage_get_voltage, +}; + +static int regulator_fixed_voltage_probe(struct platform_device *pdev) +{ + struct fixed_voltage_config *config = pdev->dev.platform_data; + struct fixed_voltage_data *drvdata; + int ret; + + drvdata = kzalloc(sizeof(struct fixed_voltage_data), GFP_KERNEL); + if (drvdata == NULL) { + ret = -ENOMEM; + goto err; + } + + drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL); + if (drvdata->desc.name == NULL) { + ret = -ENOMEM; + goto err; + } + drvdata->desc.type = REGULATOR_VOLTAGE; + drvdata->desc.owner = THIS_MODULE; + drvdata->desc.ops = &fixed_voltage_ops, + + drvdata->microvolts = config->microvolts; + + drvdata->dev = regulator_register(&drvdata->desc, drvdata); + if (IS_ERR(drvdata->dev)) { + ret = PTR_ERR(drvdata->dev); + goto err_name; + } + + platform_set_drvdata(pdev, drvdata); + + dev_dbg(&pdev->dev, "%s supplying %duV\n", drvdata->desc.name, + drvdata->microvolts); + + return 0; + +err_name: + kfree(drvdata->desc.name); +err: + kfree(drvdata); + return ret; +} + +static int regulator_fixed_voltage_remove(struct platform_device *pdev) +{ + struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev); + + regulator_unregister(drvdata->dev); + kfree(drvdata->desc.name); + kfree(drvdata); + + return 0; +} + +static struct platform_driver regulator_fixed_voltage_driver = { + .probe = regulator_fixed_voltage_probe, + .remove = regulator_fixed_voltage_remove, + .driver = { + .name = "reg-fixed-voltage", + }, +}; + +static int __init regulator_fixed_voltage_init(void) +{ + return platform_driver_register(®ulator_fixed_voltage_driver); +} +module_init(regulator_fixed_voltage_init); + +static void __exit regulator_fixed_voltage_exit(void) +{ + platform_driver_unregister(®ulator_fixed_voltage_driver); +} +module_exit(regulator_fixed_voltage_exit); + +MODULE_AUTHOR("Mark Brown "); +MODULE_DESCRIPTION("Fixed voltage regulator"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From c080909eef2b3e7fba70f57cde3264fba95bdf09 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 30 Apr 2008 17:05:33 +0100 Subject: regulator: regulator test harness This provides a virtual regulator test harness which exposes a sysfs interface for setting power requirements, intended for test purposes only. Signed-off-by: Mark Brown Signed-off-by: Philipp Zabel Signed-off-by: Liam Girdwood --- drivers/regulator/virtual.c | 345 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 345 insertions(+) create mode 100644 drivers/regulator/virtual.c (limited to 'drivers') diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c new file mode 100644 index 00000000000..5ddb464b1c3 --- /dev/null +++ b/drivers/regulator/virtual.c @@ -0,0 +1,345 @@ +/* + * reg-virtual-consumer.c + * + * Copyright 2008 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +struct virtual_consumer_data { + struct mutex lock; + struct regulator *regulator; + int enabled; + int min_uV; + int max_uV; + int min_uA; + int max_uA; + unsigned int mode; +}; + +static void update_voltage_constraints(struct virtual_consumer_data *data) +{ + int ret; + + if (data->min_uV && data->max_uV + && data->min_uV <= data->max_uV) { + ret = regulator_set_voltage(data->regulator, + data->min_uV, data->max_uV); + if (ret != 0) { + printk(KERN_ERR "regulator_set_voltage() failed: %d\n", + ret); + return; + } + } + + if (data->min_uV && data->max_uV && !data->enabled) { + ret = regulator_enable(data->regulator); + if (ret == 0) + data->enabled = 1; + else + printk(KERN_ERR "regulator_enable() failed: %d\n", + ret); + } + + if (!(data->min_uV && data->max_uV) && data->enabled) { + ret = regulator_disable(data->regulator); + if (ret == 0) + data->enabled = 0; + else + printk(KERN_ERR "regulator_disable() failed: %d\n", + ret); + } +} + +static void update_current_limit_constraints(struct virtual_consumer_data + *data) +{ + int ret; + + if (data->max_uA + && data->min_uA <= data->max_uA) { + ret = regulator_set_current_limit(data->regulator, + data->min_uA, data->max_uA); + if (ret != 0) { + pr_err("regulator_set_current_limit() failed: %d\n", + ret); + return; + } + } + + if (data->max_uA && !data->enabled) { + ret = regulator_enable(data->regulator); + if (ret == 0) + data->enabled = 1; + else + printk(KERN_ERR "regulator_enable() failed: %d\n", + ret); + } + + if (!(data->min_uA && data->max_uA) && data->enabled) { + ret = regulator_disable(data->regulator); + if (ret == 0) + data->enabled = 0; + else + printk(KERN_ERR "regulator_disable() failed: %d\n", + ret); + } +} + +static ssize_t show_min_uV(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct virtual_consumer_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", data->min_uV); +} + +static ssize_t set_min_uV(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct virtual_consumer_data *data = dev_get_drvdata(dev); + long val; + + if (strict_strtol(buf, 10, &val) != 0) + return count; + + mutex_lock(&data->lock); + + data->min_uV = val; + update_voltage_constraints(data); + + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_max_uV(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct virtual_consumer_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", data->max_uV); +} + +static ssize_t set_max_uV(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct virtual_consumer_data *data = dev_get_drvdata(dev); + long val; + + if (strict_strtol(buf, 10, &val) != 0) + return count; + + mutex_lock(&data->lock); + + data->max_uV = val; + update_voltage_constraints(data); + + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_min_uA(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct virtual_consumer_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", data->min_uA); +} + +static ssize_t set_min_uA(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct virtual_consumer_data *data = dev_get_drvdata(dev); + long val; + + if (strict_strtol(buf, 10, &val) != 0) + return count; + + mutex_lock(&data->lock); + + data->min_uA = val; + update_current_limit_constraints(data); + + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_max_uA(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct virtual_consumer_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", data->max_uA); +} + +static ssize_t set_max_uA(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct virtual_consumer_data *data = dev_get_drvdata(dev); + long val; + + if (strict_strtol(buf, 10, &val) != 0) + return count; + + mutex_lock(&data->lock); + + data->max_uA = val; + update_current_limit_constraints(data); + + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct virtual_consumer_data *data = dev_get_drvdata(dev); + + switch (data->mode) { + case REGULATOR_MODE_FAST: + return sprintf(buf, "fast\n"); + case REGULATOR_MODE_NORMAL: + return sprintf(buf, "normal\n"); + case REGULATOR_MODE_IDLE: + return sprintf(buf, "idle\n"); + case REGULATOR_MODE_STANDBY: + return sprintf(buf, "standby\n"); + default: + return sprintf(buf, "unknown\n"); + } +} + +static ssize_t set_mode(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct virtual_consumer_data *data = dev_get_drvdata(dev); + unsigned int mode; + int ret; + + if (strncmp(buf, "fast", strlen("fast")) == 0) + mode = REGULATOR_MODE_FAST; + else if (strncmp(buf, "normal", strlen("normal")) == 0) + mode = REGULATOR_MODE_NORMAL; + else if (strncmp(buf, "idle", strlen("idle")) == 0) + mode = REGULATOR_MODE_IDLE; + else if (strncmp(buf, "standby", strlen("standby")) == 0) + mode = REGULATOR_MODE_STANDBY; + else { + dev_err(dev, "Configuring invalid mode\n"); + return count; + } + + mutex_lock(&data->lock); + ret = regulator_set_mode(data->regulator, mode); + if (ret == 0) + data->mode = mode; + else + dev_err(dev, "Failed to configure mode: %d\n", ret); + mutex_unlock(&data->lock); + + return count; +} + +static DEVICE_ATTR(min_microvolts, 0666, show_min_uV, set_min_uV); +static DEVICE_ATTR(max_microvolts, 0666, show_max_uV, set_max_uV); +static DEVICE_ATTR(min_microamps, 0666, show_min_uA, set_min_uA); +static DEVICE_ATTR(max_microamps, 0666, show_max_uA, set_max_uA); +static DEVICE_ATTR(mode, 0666, show_mode, set_mode); + +struct device_attribute *attributes[] = { + &dev_attr_min_microvolts, + &dev_attr_max_microvolts, + &dev_attr_min_microamps, + &dev_attr_max_microamps, + &dev_attr_mode, +}; + +static int regulator_virtual_consumer_probe(struct platform_device *pdev) +{ + char *reg_id = pdev->dev.platform_data; + struct virtual_consumer_data *drvdata; + int ret, i; + + drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL); + if (drvdata == NULL) { + ret = -ENOMEM; + goto err; + } + + mutex_init(&drvdata->lock); + + drvdata->regulator = regulator_get(&pdev->dev, reg_id); + if (IS_ERR(drvdata->regulator)) { + ret = PTR_ERR(drvdata->regulator); + goto err; + } + + for (i = 0; i < ARRAY_SIZE(attributes); i++) { + ret = device_create_file(&pdev->dev, attributes[i]); + if (ret != 0) + goto err; + } + + drvdata->mode = regulator_get_mode(drvdata->regulator); + + platform_set_drvdata(pdev, drvdata); + + return 0; + +err: + for (i = 0; i < ARRAY_SIZE(attributes); i++) + device_remove_file(&pdev->dev, attributes[i]); + kfree(drvdata); + return ret; +} + +static int regulator_virtual_consumer_remove(struct platform_device *pdev) +{ + struct virtual_consumer_data *drvdata = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < ARRAY_SIZE(attributes); i++) + device_remove_file(&pdev->dev, attributes[i]); + if (drvdata->enabled) + regulator_disable(drvdata->regulator); + regulator_put(drvdata->regulator); + + kfree(drvdata); + + return 0; +} + +static struct platform_driver regulator_virtual_consumer_driver = { + .probe = regulator_virtual_consumer_probe, + .remove = regulator_virtual_consumer_remove, + .driver = { + .name = "reg-virt-consumer", + }, +}; + + +static int __init regulator_virtual_consumer_init(void) +{ + return platform_driver_register(®ulator_virtual_consumer_driver); +} +module_init(regulator_virtual_consumer_init); + +static void __exit regulator_virtual_consumer_exit(void) +{ + platform_driver_unregister(®ulator_virtual_consumer_driver); +} +module_exit(regulator_virtual_consumer_exit); + +MODULE_AUTHOR("Mark Brown "); +MODULE_DESCRIPTION("Virtual regulator consumer"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From ba7e4763437561763b6cca14a41f1d2a7def23e2 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 30 Apr 2008 17:13:42 +0100 Subject: regulator: core kbuild files This patch adds kernel build support for the regulator core. Signed-off-by: Philipp Zabel Signed-off-by: Liam Girdwood --- drivers/Makefile | 1 + drivers/regulator/Kconfig | 49 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/regulator/Makefile | 10 ++++++++++ 3 files changed, 60 insertions(+) create mode 100644 drivers/regulator/Kconfig create mode 100644 drivers/regulator/Makefile (limited to 'drivers') diff --git a/drivers/Makefile b/drivers/Makefile index 54ec5e718c0..a280ab3d083 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -97,3 +97,4 @@ obj-$(CONFIG_PPC_PS3) += ps3/ obj-$(CONFIG_OF) += of/ obj-$(CONFIG_SSB) += ssb/ obj-$(CONFIG_VIRTIO) += virtio/ +obj-$(CONFIG_REGULATOR) += regulator/ diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig new file mode 100644 index 00000000000..84f89ecce69 --- /dev/null +++ b/drivers/regulator/Kconfig @@ -0,0 +1,49 @@ +menu "Voltage and Current regulators" + +config REGULATOR + bool "Voltage and Current Regulator Support" + default n + help + Generic Voltage and Current Regulator support. + + This framework is designed to provide a generic interface to voltage + and current regulators within the Linux kernel. It's intended to + provide voltage and current control to client or consumer drivers and + also provide status information to user space applications through a + sysfs interface. + + The intention is to allow systems to dynamically control regulator + output in order to save power and prolong battery life. This applies + to both voltage regulators (where voltage output is controllable) and + current sinks (where current output is controllable). + + This framework safely compiles out if not selected so that client + drivers can still be used in systems with no software controllable + regulators. + + If unsure, say no. + +config REGULATOR_DEBUG + bool "Regulator debug support" + depends on REGULATOR + help + Say yes here to enable debugging support. + +config REGULATOR_FIXED_VOLTAGE + tristate + default n + select REGULATOR + +config REGULATOR_VIRTUAL_CONSUMER + tristate "Virtual regulator consumer support" + default n + select REGULATOR + help + This driver provides a virtual consumer for the voltage and + current regulator API which provides sysfs controls for + configuring the supplies requested. This is mainly useful + for test purposes. + + If unsure, say no. + +endmenu diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile new file mode 100644 index 00000000000..29528b78c8d --- /dev/null +++ b/drivers/regulator/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for regulator drivers. +# + + +obj-$(CONFIG_REGULATOR) += core.o +obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o +obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o + +ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG -- cgit v1.2.3 From 0eb5d5ab3ec99bfd22ff16797d95835369ffb25b Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 11 Jul 2008 17:28:06 +0200 Subject: regulator: TI bq24022 Li-Ion Charger driver This adds a regulator driver for the TI bq24022 Single-Chip Li-Ion Charger with its nCE and ISET2 pins connected to GPIOs. Signed-off-by: Philipp Zabel Signed-off-by: Liam Girdwood --- drivers/regulator/Kconfig | 10 +++ drivers/regulator/Makefile | 2 + drivers/regulator/bq24022.c | 167 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 drivers/regulator/bq24022.c (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 84f89ecce69..a656128f1fd 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -46,4 +46,14 @@ config REGULATOR_VIRTUAL_CONSUMER If unsure, say no. +config REGULATOR_BQ24022 + tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC" + default n + select REGULATOR + help + This driver controls a TI bq24022 Charger attached via + GPIOs. The provided current regulator can enable/disable + charging select between 100 mA and 500 mA charging current + limit. + endmenu diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 29528b78c8d..ac2c64efe65 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -7,4 +7,6 @@ obj-$(CONFIG_REGULATOR) += core.o obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o +obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o + ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/bq24022.c b/drivers/regulator/bq24022.c new file mode 100644 index 00000000000..263699d6152 --- /dev/null +++ b/drivers/regulator/bq24022.c @@ -0,0 +1,167 @@ +/* + * Support for TI bq24022 (bqTINY-II) Dual Input (USB/AC Adpater) + * 1-Cell Li-Ion Charger connected via GPIOs. + * + * Copyright (c) 2008 Philipp Zabel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +static int bq24022_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + struct platform_device *pdev = rdev_get_drvdata(rdev); + struct bq24022_mach_info *pdata = pdev->dev.platform_data; + + dev_dbg(&pdev->dev, "setting current limit to %s mA\n", + max_uA >= 500000 ? "500" : "100"); + + /* REVISIT: maybe return error if min_uA != 0 ? */ + gpio_set_value(pdata->gpio_iset2, max_uA >= 500000); + return 0; +} + +static int bq24022_get_current_limit(struct regulator_dev *rdev) +{ + struct platform_device *pdev = rdev_get_drvdata(rdev); + struct bq24022_mach_info *pdata = pdev->dev.platform_data; + + return gpio_get_value(pdata->gpio_iset2) ? 500000 : 100000; +} + +static int bq24022_enable(struct regulator_dev *rdev) +{ + struct platform_device *pdev = rdev_get_drvdata(rdev); + struct bq24022_mach_info *pdata = pdev->dev.platform_data; + + dev_dbg(&pdev->dev, "enabling charger\n"); + + gpio_set_value(pdata->gpio_nce, 0); + return 0; +} + +static int bq24022_disable(struct regulator_dev *rdev) +{ + struct platform_device *pdev = rdev_get_drvdata(rdev); + struct bq24022_mach_info *pdata = pdev->dev.platform_data; + + dev_dbg(&pdev->dev, "disabling charger\n"); + + gpio_set_value(pdata->gpio_nce, 1); + return 0; +} + +static int bq24022_is_enabled(struct regulator_dev *rdev) +{ + struct platform_device *pdev = rdev_get_drvdata(rdev); + struct bq24022_mach_info *pdata = pdev->dev.platform_data; + + return !gpio_get_value(pdata->gpio_nce); +} + +static struct regulator_ops bq24022_ops = { + .set_current_limit = bq24022_set_current_limit, + .get_current_limit = bq24022_get_current_limit, + .enable = bq24022_enable, + .disable = bq24022_disable, + .is_enabled = bq24022_is_enabled, +}; + +static struct regulator_desc bq24022_desc = { + .name = "bq24022", + .ops = &bq24022_ops, + .type = REGULATOR_CURRENT, +}; + +static int __init bq24022_probe(struct platform_device *pdev) +{ + struct bq24022_mach_info *pdata = pdev->dev.platform_data; + struct regulator_dev *bq24022; + int ret; + + if (!pdata || !pdata->gpio_nce || !pdata->gpio_iset2) + return -EINVAL; + + ret = gpio_request(pdata->gpio_nce, "ncharge_en"); + if (ret) { + dev_dbg(&pdev->dev, "couldn't request nCE GPIO: %d\n", + pdata->gpio_nce); + goto err_ce; + } + ret = gpio_request(pdata->gpio_iset2, "charge_mode"); + if (ret) { + dev_dbg(&pdev->dev, "couldn't request ISET2 GPIO: %d\n", + pdata->gpio_iset2); + goto err_iset2; + } + ret = gpio_direction_output(pdata->gpio_iset2, 0); + ret = gpio_direction_output(pdata->gpio_nce, 1); + + bq24022 = regulator_register(&bq24022_desc, pdev); + if (IS_ERR(bq24022)) { + dev_dbg(&pdev->dev, "couldn't register regulator\n"); + ret = PTR_ERR(bq24022); + goto err_reg; + } + platform_set_drvdata(pdev, bq24022); + dev_dbg(&pdev->dev, "registered regulator\n"); + + return 0; +err_reg: + gpio_free(pdata->gpio_iset2); +err_iset2: + gpio_free(pdata->gpio_nce); +err_ce: + return ret; +} + +static int __devexit bq24022_remove(struct platform_device *pdev) +{ + struct bq24022_mach_info *pdata = pdev->dev.platform_data; + struct regulator_dev *bq24022 = platform_get_drvdata(pdev); + + regulator_unregister(bq24022); + gpio_free(pdata->gpio_iset2); + gpio_free(pdata->gpio_nce); + + return 0; +} + +static struct platform_driver bq24022_driver = { + .driver = { + .name = "bq24022", + }, + .remove = __devexit_p(bq24022_remove), +}; + +static int __init bq24022_init(void) +{ + return platform_driver_probe(&bq24022_driver, bq24022_probe); +} + +static void __exit bq24022_exit(void) +{ + platform_driver_unregister(&bq24022_driver); +} + +/* + * make sure this is probed before gpio_vbus and pda_power, + * but after asic3 or other GPIO expander drivers. + */ +subsys_initcall(bq24022_init); +module_exit(bq24022_exit); + +MODULE_AUTHOR("Philipp Zabel"); +MODULE_DESCRIPTION("TI bq24022 Li-Ion Charger driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 74216be41a61a809ad17b091068307e3d89f4a2f Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 30 Jul 2008 11:18:42 +0300 Subject: [MTD] [NAND] nandsim: support random page read command Commit 3d45955962496879dead8d4dd70bb9a23b07154b ("subpage read feature as a way to improve performance") broke nandsim because nandsim does not support the "random page read" NAND command. This patch adds corresponding support. Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nandsim.c | 57 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index ecd70e2504f..7428a6c1135 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -207,13 +207,16 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I #define STATE_CMD_READID 0x0000000A /* read ID */ #define STATE_CMD_ERASE2 0x0000000B /* sector erase second command */ #define STATE_CMD_RESET 0x0000000C /* reset */ +#define STATE_CMD_RNDOUT 0x0000000D /* random output command */ +#define STATE_CMD_RNDOUTSTART 0x0000000E /* random output start command */ #define STATE_CMD_MASK 0x0000000F /* command states mask */ /* After an address is input, the simulator goes to one of these states */ #define STATE_ADDR_PAGE 0x00000010 /* full (row, column) address is accepted */ #define STATE_ADDR_SEC 0x00000020 /* sector address was accepted */ -#define STATE_ADDR_ZERO 0x00000030 /* one byte zero address was accepted */ -#define STATE_ADDR_MASK 0x00000030 /* address states mask */ +#define STATE_ADDR_COLUMN 0x00000030 /* column address was accepted */ +#define STATE_ADDR_ZERO 0x00000040 /* one byte zero address was accepted */ +#define STATE_ADDR_MASK 0x00000070 /* address states mask */ /* Durind data input/output the simulator is in these states */ #define STATE_DATAIN 0x00000100 /* waiting for data input */ @@ -240,7 +243,7 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I #define ACTION_OOBOFF 0x00600000 /* add to address OOB offset */ #define ACTION_MASK 0x00700000 /* action mask */ -#define NS_OPER_NUM 12 /* Number of operations supported by the simulator */ +#define NS_OPER_NUM 13 /* Number of operations supported by the simulator */ #define NS_OPER_STATES 6 /* Maximum number of states in operation */ #define OPT_ANY 0xFFFFFFFF /* any chip supports this operation */ @@ -373,7 +376,10 @@ static struct nandsim_operations { {OPT_ANY, {STATE_CMD_READID, STATE_ADDR_ZERO, STATE_DATAOUT_ID, STATE_READY}}, /* Large page devices read page */ {OPT_LARGEPAGE, {STATE_CMD_READ0, STATE_ADDR_PAGE, STATE_CMD_READSTART | ACTION_CPY, - STATE_DATAOUT, STATE_READY}} + STATE_DATAOUT, STATE_READY}}, + /* Large page devices random page read */ + {OPT_LARGEPAGE, {STATE_CMD_RNDOUT, STATE_ADDR_COLUMN, STATE_CMD_RNDOUTSTART | ACTION_CPY, + STATE_DATAOUT, STATE_READY}}, }; struct weak_block { @@ -937,12 +943,18 @@ static char *get_state_name(uint32_t state) return "STATE_CMD_ERASE2"; case STATE_CMD_RESET: return "STATE_CMD_RESET"; + case STATE_CMD_RNDOUT: + return "STATE_CMD_RNDOUT"; + case STATE_CMD_RNDOUTSTART: + return "STATE_CMD_RNDOUTSTART"; case STATE_ADDR_PAGE: return "STATE_ADDR_PAGE"; case STATE_ADDR_SEC: return "STATE_ADDR_SEC"; case STATE_ADDR_ZERO: return "STATE_ADDR_ZERO"; + case STATE_ADDR_COLUMN: + return "STATE_ADDR_COLUMN"; case STATE_DATAIN: return "STATE_DATAIN"; case STATE_DATAOUT: @@ -973,6 +985,7 @@ static int check_command(int cmd) switch (cmd) { case NAND_CMD_READ0: + case NAND_CMD_READ1: case NAND_CMD_READSTART: case NAND_CMD_PAGEPROG: case NAND_CMD_READOOB: @@ -982,7 +995,8 @@ static int check_command(int cmd) case NAND_CMD_READID: case NAND_CMD_ERASE2: case NAND_CMD_RESET: - case NAND_CMD_READ1: + case NAND_CMD_RNDOUT: + case NAND_CMD_RNDOUTSTART: return 0; case NAND_CMD_STATUS_MULTI: @@ -1021,6 +1035,10 @@ static uint32_t get_state_by_command(unsigned command) return STATE_CMD_ERASE2; case NAND_CMD_RESET: return STATE_CMD_RESET; + case NAND_CMD_RNDOUT: + return STATE_CMD_RNDOUT; + case NAND_CMD_RNDOUTSTART: + return STATE_CMD_RNDOUTSTART; } NS_ERR("get_state_by_command: unknown command, BUG\n"); @@ -1582,6 +1600,11 @@ static void switch_state(struct nandsim *ns) ns->regs.num = 1; break; + case STATE_ADDR_COLUMN: + /* Column address is always 2 bytes */ + ns->regs.num = ns->geom.pgaddrbytes - ns->geom.secaddrbytes; + break; + default: NS_ERR("switch_state: BUG! unknown address state\n"); } @@ -1693,15 +1716,21 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte) return; } - /* - * Chip might still be in STATE_DATAOUT - * (if OPT_AUTOINCR feature is supported), STATE_DATAOUT_STATUS or - * STATE_DATAOUT_STATUS_M state. If so, switch state. - */ + /* Check that the command byte is correct */ + if (check_command(byte)) { + NS_ERR("write_byte: unknown command %#x\n", (uint)byte); + return; + } + if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS || NS_STATE(ns->state) == STATE_DATAOUT_STATUS_M - || ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT)) + || NS_STATE(ns->state) == STATE_DATAOUT) { + int row = ns->regs.row; + switch_state(ns); + if (byte == NAND_CMD_RNDOUT) + ns->regs.row = row; + } /* Check if chip is expecting command */ if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) { @@ -1715,12 +1744,6 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte) switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); } - /* Check that the command byte is correct */ - if (check_command(byte)) { - NS_ERR("write_byte: unknown command %#x\n", (uint)byte); - return; - } - NS_DBG("command byte corresponding to %s state accepted\n", get_state_name(get_state_by_command(byte))); ns->regs.command = byte; -- cgit v1.2.3 From 650da9d0b7c401619c1df2953e975606b8d5dcbb Mon Sep 17 00:00:00 2001 From: "akpm@linux-foundation.org" Date: Tue, 29 Jul 2008 21:27:14 -0700 Subject: [MTD] [NAND] fsl_elbc_nand.c: fix printk warning drivers/mtd/nand/fsl_elbc_nand.c:890: warning: format '%x' expects type 'unsigned int', but argument 3 has type 'resource_size_t' Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsl_elbc_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 9dff51351f4..98ad3cefcaf 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -887,7 +887,7 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, goto err; } - priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", res.start); + priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", (unsigned)res.start); if (!priv->mtd.name) { ret = -ENOMEM; goto err; -- cgit v1.2.3 From 771999b65f79264acde4b855e5d35696eca5e80c Mon Sep 17 00:00:00 2001 From: "akpm@linux-foundation.org" Date: Tue, 29 Jul 2008 22:22:40 -0700 Subject: [MTD] DataFlash: bugfix, binary page sizes now handled The wrong version of the "teach dataflash about binary density" patch just got merged (v2 not v3) ... this restores the missing updates: * Fix the cmdlinepart *regression* that caused testing failures (!!) by restoring the original part labels in relevant cases. * Don't reference things that don't exist (!) - An opcode that doesn't even exist for DataFlash - The part is "at45db642" not "at45db641" - ID zero in this JEDEC table * Make the JEDEC probe routine report and handle errors better: - If the SPI calls fail, return the error codes. - Don't depend on ordering of table entries. - Unrecognized ids are different from parts that have no ID. We won't actually know how to handle them correctly; display the ID and ignore the chip. * Move the original block comment about the "legacy" chip ID scheme back next to the code to which it applies ... not next to the new JEDEC query code, which uses an entirely different strategy. * Don't print a guessed erasesize; /proc/mtd has the real value. And add a few more comments. Signed-off-by: David Brownell Cc: Bryan Wu Cc: Michael Hennerich Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/devices/mtd_dataflash.c | 130 +++++++++++++++++++++++------------- 1 file changed, 83 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 54e36bfc2c3..8bd0dea6885 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -15,6 +15,8 @@ #include #include #include +#include + #include #include @@ -487,9 +489,8 @@ add_dataflash(struct spi_device *spi, char *name, device->write = dataflash_write; device->priv = priv; - dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes, " - "erasesize %d bytes\n", name, device->size/1024, - pagesize, pagesize * 8); /* 8 pages = 1 block */ + dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes\n", + name, DIV_ROUND_UP(device->size, 1024), pagesize); dev_set_drvdata(&spi->dev, priv); if (mtd_has_partitions()) { @@ -518,65 +519,57 @@ add_dataflash(struct spi_device *spi, char *name, return add_mtd_device(device) == 1 ? -ENODEV : 0; } -/* - * Detect and initialize DataFlash device: - * - * Device Density ID code #Pages PageSize Offset - * AT45DB011B 1Mbit (128K) xx0011xx (0x0c) 512 264 9 - * AT45DB021B 2Mbit (256K) xx0101xx (0x14) 1024 264 9 - * AT45DB041B 4Mbit (512K) xx0111xx (0x1c) 2048 264 9 - * AT45DB081B 8Mbit (1M) xx1001xx (0x24) 4096 264 9 - * AT45DB0161B 16Mbit (2M) xx1011xx (0x2c) 4096 528 10 - * AT45DB0321B 32Mbit (4M) xx1101xx (0x34) 8192 528 10 - * AT45DB0642 64Mbit (8M) xx111xxx (0x3c) 8192 1056 11 - * AT45DB1282 128Mbit (16M) xx0100xx (0x10) 16384 1056 11 - */ - struct flash_info { char *name; - /* JEDEC id zero means "no ID" (most older chips); otherwise it has - * a high byte of zero plus three data bytes: the manufacturer id, - * then a two byte device id. + /* JEDEC id has a high byte of zero plus three data bytes: + * the manufacturer id, then a two byte device id. */ uint32_t jedec_id; - /* The size listed here is what works with OPCODE_SE, which isn't - * necessarily called a "sector" by the vendor. - */ + /* The size listed here is what works with OP_ERASE_PAGE. */ unsigned nr_pages; uint16_t pagesize; uint16_t pageoffset; uint16_t flags; -#define SUP_POW2PS 0x02 -#define IS_POW2PS 0x01 +#define SUP_POW2PS 0x0002 /* supports 2^N byte pages */ +#define IS_POW2PS 0x0001 /* uses 2^N byte pages */ }; static struct flash_info __devinitdata dataflash_data [] = { - { "at45db011d", 0x1f2200, 512, 264, 9, SUP_POW2PS}, + /* + * NOTE: chips with SUP_POW2PS (rev D and up) need two entries, + * one with IS_POW2PS and the other without. The entry with the + * non-2^N byte page size can't name exact chip revisions without + * losing backwards compatibility for cmdlinepart. + * + * These newer chips also support 128-byte security registers (with + * 64 bytes one-time-programmable) and software write-protection. + */ + { "AT45DB011B", 0x1f2200, 512, 264, 9, SUP_POW2PS}, { "at45db011d", 0x1f2200, 512, 256, 8, SUP_POW2PS | IS_POW2PS}, - { "at45db021d", 0x1f2300, 1024, 264, 9, SUP_POW2PS}, + { "AT45DB021B", 0x1f2300, 1024, 264, 9, SUP_POW2PS}, { "at45db021d", 0x1f2300, 1024, 256, 8, SUP_POW2PS | IS_POW2PS}, - { "at45db041d", 0x1f2400, 2048, 264, 9, SUP_POW2PS}, + { "AT45DB041x", 0x1f2400, 2048, 264, 9, SUP_POW2PS}, { "at45db041d", 0x1f2400, 2048, 256, 8, SUP_POW2PS | IS_POW2PS}, - { "at45db081d", 0x1f2500, 4096, 264, 9, SUP_POW2PS}, + { "AT45DB081B", 0x1f2500, 4096, 264, 9, SUP_POW2PS}, { "at45db081d", 0x1f2500, 4096, 256, 8, SUP_POW2PS | IS_POW2PS}, - { "at45db161d", 0x1f2600, 4096, 528, 10, SUP_POW2PS}, + { "AT45DB161x", 0x1f2600, 4096, 528, 10, SUP_POW2PS}, { "at45db161d", 0x1f2600, 4096, 512, 9, SUP_POW2PS | IS_POW2PS}, - { "at45db321c", 0x1f2700, 8192, 528, 10, }, + { "AT45DB321x", 0x1f2700, 8192, 528, 10, 0}, /* rev C */ - { "at45db321d", 0x1f2701, 8192, 528, 10, SUP_POW2PS}, + { "AT45DB321x", 0x1f2701, 8192, 528, 10, SUP_POW2PS}, { "at45db321d", 0x1f2701, 8192, 512, 9, SUP_POW2PS | IS_POW2PS}, - { "at45db641d", 0x1f2800, 8192, 1056, 11, SUP_POW2PS}, - { "at45db641d", 0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS}, + { "AT45DB642x", 0x1f2800, 8192, 1056, 11, SUP_POW2PS}, + { "at45db642d", 0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS}, }; static struct flash_info *__devinit jedec_probe(struct spi_device *spi) @@ -588,17 +581,23 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi) struct flash_info *info; int status; - /* JEDEC also defines an optional "extended device information" * string for after vendor-specific data, after the three bytes * we use here. Supporting some chips might require using it. + * + * If the vendor ID isn't Atmel's (0x1f), assume this call failed. + * That's not an error; only rev C and newer chips handle it, and + * only Atmel sells these chips. */ tmp = spi_write_then_read(spi, &code, 1, id, 3); if (tmp < 0) { DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n", spi->dev.bus_id, tmp); - return NULL; + return ERR_PTR(tmp); } + if (id[0] != 0x1f) + return NULL; + jedec = id[0]; jedec = jedec << 8; jedec |= id[1]; @@ -609,19 +608,53 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi) tmp < ARRAY_SIZE(dataflash_data); tmp++, info++) { if (info->jedec_id == jedec) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: OTP, sector protect%s\n", + dev_name(&spi->dev), + (info->flags & SUP_POW2PS) + ? ", binary pagesize" : "" + ); if (info->flags & SUP_POW2PS) { status = dataflash_status(spi); - if (status & 0x1) - /* return power of 2 pagesize */ - return ++info; - else - return info; + if (status < 0) { + DEBUG(MTD_DEBUG_LEVEL1, + "%s: status error %d\n", + dev_name(&spi->dev), status); + return ERR_PTR(status); + } + if (status & 0x1) { + if (info->flags & IS_POW2PS) + return info; + } else { + if (!(info->flags & IS_POW2PS)) + return info; + } } } } - return NULL; + + /* + * Treat other chips as errors ... we won't know the right page + * size (it might be binary) even when we can tell which density + * class is involved (legacy chip id scheme). + */ + dev_warn(&spi->dev, "JEDEC id %06x not handled\n", jedec); + return ERR_PTR(-ENODEV); } +/* + * Detect and initialize DataFlash device, using JEDEC IDs on newer chips + * or else the ID code embedded in the status bits: + * + * Device Density ID code #Pages PageSize Offset + * AT45DB011B 1Mbit (128K) xx0011xx (0x0c) 512 264 9 + * AT45DB021B 2Mbit (256K) xx0101xx (0x14) 1024 264 9 + * AT45DB041B 4Mbit (512K) xx0111xx (0x1c) 2048 264 9 + * AT45DB081B 8Mbit (1M) xx1001xx (0x24) 4096 264 9 + * AT45DB0161B 16Mbit (2M) xx1011xx (0x2c) 4096 528 10 + * AT45DB0321B 32Mbit (4M) xx1101xx (0x34) 8192 528 10 + * AT45DB0642 64Mbit (8M) xx111xxx (0x3c) 8192 1056 11 + * AT45DB1282 128Mbit (16M) xx0100xx (0x10) 16384 1056 11 + */ static int __devinit dataflash_probe(struct spi_device *spi) { int status; @@ -632,14 +665,17 @@ static int __devinit dataflash_probe(struct spi_device *spi) * If it succeeds we know we have either a C or D part. * D will support power of 2 pagesize option. */ - info = jedec_probe(spi); - + if (IS_ERR(info)) + return PTR_ERR(info); if (info != NULL) return add_dataflash(spi, info->name, info->nr_pages, info->pagesize, info->pageoffset); - + /* + * Older chips support only legacy commands, identifing + * capacity using bits in the status byte. + */ status = dataflash_status(spi); if (status <= 0 || status == 0xff) { DEBUG(MTD_DEBUG_LEVEL1, "%s: status error %d\n", @@ -661,13 +697,13 @@ static int __devinit dataflash_probe(struct spi_device *spi) status = add_dataflash(spi, "AT45DB021B", 1024, 264, 9); break; case 0x1c: /* 0 1 1 1 x x */ - status = add_dataflash(spi, "AT45DB041B", 2048, 264, 9); + status = add_dataflash(spi, "AT45DB041x", 2048, 264, 9); break; case 0x24: /* 1 0 0 1 x x */ status = add_dataflash(spi, "AT45DB081B", 4096, 264, 9); break; case 0x2c: /* 1 0 1 1 x x */ - status = add_dataflash(spi, "AT45DB161B", 4096, 528, 10); + status = add_dataflash(spi, "AT45DB161x", 4096, 528, 10); break; case 0x34: /* 1 1 0 1 x x */ status = add_dataflash(spi, "AT45DB321x", 8192, 528, 10); -- cgit v1.2.3 From dd07428b44944b42f699408fe31af47977f1e733 Mon Sep 17 00:00:00 2001 From: HighPoint Linux Team Date: Fri, 25 Jul 2008 13:29:24 +0800 Subject: [SCSI] hptiop: add more PCI device IDs Add PCI device ID for new adapter models. Signed-off-by: HighPoint Linux Team Cc: Stable Tree Signed-off-by: James Bottomley --- drivers/scsi/hptiop.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index da876d3924b..74d12b58a26 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -1249,6 +1249,13 @@ static struct pci_device_id hptiop_id_table[] = { { PCI_VDEVICE(TTI, 0x3522), (kernel_ulong_t)&hptiop_itl_ops }, { PCI_VDEVICE(TTI, 0x3410), (kernel_ulong_t)&hptiop_itl_ops }, { PCI_VDEVICE(TTI, 0x3540), (kernel_ulong_t)&hptiop_itl_ops }, + { PCI_VDEVICE(TTI, 0x3530), (kernel_ulong_t)&hptiop_itl_ops }, + { PCI_VDEVICE(TTI, 0x3560), (kernel_ulong_t)&hptiop_itl_ops }, + { PCI_VDEVICE(TTI, 0x4322), (kernel_ulong_t)&hptiop_itl_ops }, + { PCI_VDEVICE(TTI, 0x4210), (kernel_ulong_t)&hptiop_itl_ops }, + { PCI_VDEVICE(TTI, 0x4211), (kernel_ulong_t)&hptiop_itl_ops }, + { PCI_VDEVICE(TTI, 0x4310), (kernel_ulong_t)&hptiop_itl_ops }, + { PCI_VDEVICE(TTI, 0x4311), (kernel_ulong_t)&hptiop_itl_ops }, { PCI_VDEVICE(TTI, 0x3120), (kernel_ulong_t)&hptiop_mv_ops }, { PCI_VDEVICE(TTI, 0x3122), (kernel_ulong_t)&hptiop_mv_ops }, { PCI_VDEVICE(TTI, 0x3020), (kernel_ulong_t)&hptiop_mv_ops }, -- cgit v1.2.3 From 671a99c8eb2f1dde08ac5538d8cd912047c61ddf Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 29 Jul 2008 11:38:25 -0500 Subject: [SCSI] ses: fix VPD inquiry overrun There are a few kerneloops.org reports like this one: http://www.kerneloops.org/search.php?search=ses_match_to_enclosure That seem to imply we're running off the end of the VPD inquiry data (although at 512 bytes, it should be long enough for just about anything). we should be using correctly sized buffers anyway, so put those in and hope this oops goes away. Cc: Stable Tree Signed-off-by: James Bottomley --- drivers/scsi/ses.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 0fe031f003e..1bcf3c33d7f 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -345,14 +345,14 @@ static int ses_enclosure_find_by_addr(struct enclosure_device *edev, return 0; } -#define VPD_INQUIRY_SIZE 512 +#define VPD_INQUIRY_SIZE 36 static void ses_match_to_enclosure(struct enclosure_device *edev, struct scsi_device *sdev) { unsigned char *buf = kmalloc(VPD_INQUIRY_SIZE, GFP_KERNEL); unsigned char *desc; - int len; + u16 vpd_len; struct efd efd = { .addr = 0, }; @@ -372,9 +372,19 @@ static void ses_match_to_enclosure(struct enclosure_device *edev, VPD_INQUIRY_SIZE, NULL, SES_TIMEOUT, SES_RETRIES)) goto free; - len = (buf[2] << 8) + buf[3]; + vpd_len = (buf[2] << 8) + buf[3]; + kfree(buf); + buf = kmalloc(vpd_len, GFP_KERNEL); + if (!buf) + return; + cmd[3] = vpd_len >> 8; + cmd[4] = vpd_len & 0xff; + if (scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, + vpd_len, NULL, SES_TIMEOUT, SES_RETRIES)) + goto free; + desc = buf + 4; - while (desc < buf + len) { + while (desc < buf + vpd_len) { enum scsi_protocol proto = desc[0] >> 4; u8 code_set = desc[0] & 0x0f; u8 piv = desc[1] & 0x80; -- cgit v1.2.3 From e8bac9e0647dd04c83fd0bfe7cdfe2f6dfb100d0 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 29 Jul 2008 12:52:20 -0500 Subject: [SCSI] scsi_transport_spi: fix oops in revalidate The class_device->device conversion is causing an oops in revalidate because it's assuming that the device_for_each_child iterator will only return struct scsi_device children. The conversion made all former class_devices children of the device as well, so this assumption is broken. Fix it. Cc: Stable Tree Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_spi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 75a64a6cae8..b29360ed0bd 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -366,12 +366,14 @@ spi_transport_rd_attr(rti, "%d\n"); spi_transport_rd_attr(pcomp_en, "%d\n"); spi_transport_rd_attr(hold_mcs, "%d\n"); -/* we only care about the first child device so we return 1 */ +/* we only care about the first child device that's a real SCSI device + * so we return 1 to terminate the iteration when we find it */ static int child_iter(struct device *dev, void *data) { - struct scsi_device *sdev = to_scsi_device(dev); + if (!scsi_is_sdev_device(dev)) + return 0; - spi_dv_device(sdev); + spi_dv_device(to_scsi_device(dev)); return 1; } -- cgit v1.2.3 From e958d3ace7791f33518f0259cd3cf229408b135c Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 29 Jul 2008 22:32:56 -0700 Subject: backlight: give platform_lcd the same name as the platform device. When registering an platform_lcd, use the name of the platform device specified in case there are more than one platform_lcd backlights registered. Signed-off-by: Ben Dooks Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/platform_lcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c index 72d44dbfce8..29d7121e327 100644 --- a/drivers/video/backlight/platform_lcd.c +++ b/drivers/video/backlight/platform_lcd.c @@ -92,7 +92,7 @@ static int __devinit platform_lcd_probe(struct platform_device *pdev) plcd->us = dev; plcd->pdata = pdata; - plcd->lcd = lcd_device_register("platform-lcd", dev, + plcd->lcd = lcd_device_register(dev_name(dev), dev, plcd, &platform_lcd_ops); if (IS_ERR(plcd->lcd)) { dev_err(dev, "cannot register lcd device\n"); -- cgit v1.2.3 From a1531acd43310a7e4571d52e8846640667f4c74b Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Tue, 29 Jul 2008 22:32:58 -0700 Subject: cpufreq acpi: only call _PPC after cpufreq ACPI init funcs got called already Ingo Molnar provided a fix to not call _PPC at processor driver initialization time in "[PATCH] ACPI: fix cpufreq regression" (git commit e4233dec749a3519069d9390561b5636a75c7579) But it can still happen that _PPC is called at processor driver initialization time. This patch should make sure that this is not possible anymore. Signed-off-by: Thomas Renninger Cc: Andi Kleen Cc: Len Brown Cc: Dave Jones Cc: Ingo Molnar Cc: Venkatesh Pallipadi Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/acpi/processor_perflib.c | 15 +++++++++++++-- drivers/cpufreq/cpufreq.c | 3 +++ 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index b4749969c6b..e98071a6481 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -64,7 +64,13 @@ static DEFINE_MUTEX(performance_mutex); * policy is adjusted accordingly. */ -static unsigned int ignore_ppc = 0; +/* ignore_ppc: + * -1 -> cpufreq low level drivers not initialized -> _PSS, etc. not called yet + * ignore _PPC + * 0 -> cpufreq low level drivers initialized -> consider _PPC values + * 1 -> ignore _PPC totally -> forced by user through boot param + */ +static unsigned int ignore_ppc = -1; module_param(ignore_ppc, uint, 0644); MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \ "limited by BIOS, this should help"); @@ -72,7 +78,7 @@ MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \ #define PPC_REGISTERED 1 #define PPC_IN_USE 2 -static int acpi_processor_ppc_status = 0; +static int acpi_processor_ppc_status; static int acpi_processor_ppc_notifier(struct notifier_block *nb, unsigned long event, void *data) @@ -81,6 +87,11 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb, struct acpi_processor *pr; unsigned int ppc = 0; + if (event == CPUFREQ_START && ignore_ppc <= 0) { + ignore_ppc = 0; + return 0; + } + if (ignore_ppc) return 0; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 8d6a3ff0267..8a67f16987d 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -825,6 +825,9 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) policy->user_policy.min = policy->cpuinfo.min_freq; policy->user_policy.max = policy->cpuinfo.max_freq; + blocking_notifier_call_chain(&cpufreq_policy_notifier_list, + CPUFREQ_START, policy); + #ifdef CONFIG_SMP #ifdef CONFIG_HOTPLUG_CPU -- cgit v1.2.3 From 9b67c5d48f104aae6118bbb052dd79a15ab9794b Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Tue, 29 Jul 2008 22:32:59 -0700 Subject: acpi cpufreq cleanup: move bailing out of function before locking the mutex Signed-off-by: Thomas Renninger Cc: Andi Kleen Cc: Len Brown Cc: Dave Jones Cc: Ingo Molnar Cc: Venkatesh Pallipadi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/acpi/processor_perflib.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index e98071a6481..0133af49cf0 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -95,10 +95,10 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb, if (ignore_ppc) return 0; - mutex_lock(&performance_mutex); - if (event != CPUFREQ_INCOMPATIBLE) - goto out; + return 0; + + mutex_lock(&performance_mutex); pr = per_cpu(processors, policy->cpu); if (!pr || !pr->performance) -- cgit v1.2.3 From fdac4e69a1fc181652b37ce6a32ab8a56b0f3bcf Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 29 Jul 2008 22:33:01 -0700 Subject: sticore: don't activate unsupported GSC STI cards on HPPA On HPPA there exists some older GSC graphics cards, which need special graphic-card-BIOS patching to become supported. Since we don't have yet implemented the patching, it's better to detect such cards in advance, inform to the user that there are known problems and to not activate the card. Problematic GSC cards and BIOS versions are: * Hyperdrive/Hyperbowl (A4071A) graphics card series: * ID = 0x2BCB015A (Version 8.04/8) * ID = 0x2BCB015A (Version 8.04/11) * Thunder 1 VISUALIZE 48 card: * ID = 0x2F23E5FC (Version 8.05/9) * Thunder 2 VISUALIZE 48 XP card: * ID = 0x2F8D570E (Version 8.05/12) * Some Hyperion and ThunderHawk GSC cards Further details are described here: http://parisc-linux.org/faq/graphics-howto.html Signed-off-by: Helge Deller Cc: Kyle McMartin Cc: Krzysztof Helt Cc: "Antonino A. Daplas" Cc: Grant Grundler Cc: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/console/sticore.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c index d7822af0e00..ef7870f5ea0 100644 --- a/drivers/video/console/sticore.c +++ b/drivers/video/console/sticore.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "../sticore.h" @@ -725,6 +726,7 @@ static int __devinit sti_read_rom(int wordmode, struct sti_struct *sti, { struct sti_cooked_rom *cooked; struct sti_rom *raw = NULL; + unsigned long revno; cooked = kmalloc(sizeof *cooked, GFP_KERNEL); if (!cooked) @@ -767,9 +769,35 @@ static int __devinit sti_read_rom(int wordmode, struct sti_struct *sti, sti->graphics_id[1] = raw->graphics_id[1]; sti_dump_rom(raw); - + + /* check if the ROM routines in this card are compatible */ + if (wordmode || sti->graphics_id[1] != 0x09A02587) + goto ok; + + revno = (raw->revno[0] << 8) | raw->revno[1]; + + switch (sti->graphics_id[0]) { + case S9000_ID_HCRX: + /* HyperA or HyperB ? */ + if (revno == 0x8408 || revno == 0x840b) + goto msg_not_supported; + break; + case CRT_ID_THUNDER: + if (revno == 0x8509) + goto msg_not_supported; + break; + case CRT_ID_THUNDER2: + if (revno == 0x850c) + goto msg_not_supported; + } +ok: return 1; +msg_not_supported: + printk(KERN_ERR "Sorry, this GSC/STI card is not yet supported.\n"); + printk(KERN_ERR "Please see http://parisc-linux.org/faq/" + "graphics-howto.html for more info.\n"); + /* fall through */ out_err: kfree(raw); kfree(cooked); -- cgit v1.2.3 From 126ed36d0edee41c0775906a164ad7e8bef55864 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 29 Jul 2008 22:33:25 -0700 Subject: backlight: ensure platform_lcd on by default It seems that we need to ensure that the lcd is powered up at start, otherwise we do not see a display. Signed-off-by: Ben Dooks Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/platform_lcd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c index 29d7121e327..738694d2388 100644 --- a/drivers/video/backlight/platform_lcd.c +++ b/drivers/video/backlight/platform_lcd.c @@ -101,6 +101,8 @@ static int __devinit platform_lcd_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, plcd); + platform_lcd_set_power(plcd->lcd, FB_BLANK_NORMAL); + return 0; err_mem: -- cgit v1.2.3 From 26c131c71e31973e273adde4027e6a80bde164dc Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Tue, 29 Jul 2008 22:33:25 -0700 Subject: iscsi_ibft_find: fix modpost warning Exporting __init functions is wrong. Signed-off-by: Jan Beulich Acked-by: Konrad Rzeszutek Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/firmware/iscsi_ibft_find.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c index 11f17440fea..d53fbbfefa3 100644 --- a/drivers/firmware/iscsi_ibft_find.c +++ b/drivers/firmware/iscsi_ibft_find.c @@ -81,4 +81,3 @@ void __init reserve_ibft_region(void) if (ibft_addr) reserve_bootmem(pos, PAGE_ALIGN(len), BOOTMEM_DEFAULT); } -EXPORT_SYMBOL_GPL(reserve_ibft_region); -- cgit v1.2.3 From d667b6ddbcdc036a27407c8b2c1243f1dfd69e26 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 29 Jul 2008 22:33:26 -0700 Subject: hpwdt: don't use static flags Static (read: global) is potential problem. Two threads can corrupt each other's interrupt status, better avoid this. Signed-off-by: Alexey Dobriyan Cc: Wim Van Sebroeck Cc: Thomas Mingarelli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/watchdog/hpwdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index eaa3f2a79ff..ccd6c530782 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -420,7 +420,7 @@ static int __devinit detect_cru_service(void) static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason, void *data) { - static unsigned long rom_pl; + unsigned long rom_pl; static int die_nmi_called; if (ulReason != DIE_NMI && ulReason != DIE_NMI_IPI) -- cgit v1.2.3 From 950d442ad053e660538cdaa6efc0e060c2a65062 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Jul 2008 22:33:28 -0700 Subject: drivers/video: release mutex in error handling code The mutex is released on a successful return, so it would seem that it should be released on an error return as well. The semantic patch finds this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ expression l; @@ mutex_lock(l); ... when != mutex_unlock(l) when any when strict ( if (...) { ... when != mutex_unlock(l) + mutex_unlock(l); return ...; } | mutex_unlock(l); ) // Signed-off-by: Julia Lawall Acked-by: Krzysztof Helt Acked-by: Ondrej Zajicek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/arkfb.c | 9 +++------ drivers/video/vt8623fb.c | 9 +++------ 2 files changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index 5001bd4ef46..38a1e8308c8 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -1126,11 +1126,8 @@ static int ark_pci_resume (struct pci_dev* dev) acquire_console_sem(); mutex_lock(&(par->open_lock)); - if (par->ref_count == 0) { - mutex_unlock(&(par->open_lock)); - release_console_sem(); - return 0; - } + if (par->ref_count == 0) + goto fail; pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); @@ -1143,8 +1140,8 @@ static int ark_pci_resume (struct pci_dev* dev) arkfb_set_par(info); fb_set_suspend(info, 0); - mutex_unlock(&(par->open_lock)); fail: + mutex_unlock(&(par->open_lock)); release_console_sem(); return 0; } diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index 536ab11623f..4a484ee98f8 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -853,11 +853,8 @@ static int vt8623_pci_resume(struct pci_dev* dev) acquire_console_sem(); mutex_lock(&(par->open_lock)); - if (par->ref_count == 0) { - mutex_unlock(&(par->open_lock)); - release_console_sem(); - return 0; - } + if (par->ref_count == 0) + goto fail; pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); @@ -870,8 +867,8 @@ static int vt8623_pci_resume(struct pci_dev* dev) vt8623fb_set_par(info); fb_set_suspend(info, 0); - mutex_unlock(&(par->open_lock)); fail: + mutex_unlock(&(par->open_lock)); release_console_sem(); return 0; -- cgit v1.2.3 From b68bb2632453a9ca7d10a00d79adf60968cb4c05 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 29 Jul 2008 22:33:30 -0700 Subject: rtc: don't return -EBUSY when mutex_lock_interruptible() fails It was pointed out that the RTC framework handles its mutex locks oddly ... returning -EBUSY when interrupted. This fixes that by returning the value of mutex_lock_interruptible() (i.e. -EINTR). Signed-off-by: David Brownell Acked-by: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/interface.c | 10 +++++----- drivers/rtc/rtc-dev.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index d397fa5f3a9..7af60b98d8a 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -20,7 +20,7 @@ int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) err = mutex_lock_interruptible(&rtc->ops_lock); if (err) - return -EBUSY; + return err; if (!rtc->ops) err = -ENODEV; @@ -46,7 +46,7 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) err = mutex_lock_interruptible(&rtc->ops_lock); if (err) - return -EBUSY; + return err; if (!rtc->ops) err = -ENODEV; @@ -66,7 +66,7 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) err = mutex_lock_interruptible(&rtc->ops_lock); if (err) - return -EBUSY; + return err; if (!rtc->ops) err = -ENODEV; @@ -106,7 +106,7 @@ static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *al err = mutex_lock_interruptible(&rtc->ops_lock); if (err) - return -EBUSY; + return err; if (rtc->ops == NULL) err = -ENODEV; @@ -293,7 +293,7 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) err = mutex_lock_interruptible(&rtc->ops_lock); if (err) - return -EBUSY; + return err; if (!rtc->ops) err = -ENODEV; diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 0a870b7e5c3..ae3bd4de767 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -221,7 +221,7 @@ static long rtc_dev_ioctl(struct file *file, err = mutex_lock_interruptible(&rtc->ops_lock); if (err) - return -EBUSY; + return err; /* check that the calling task has appropriate permissions * for certain ioctls. doing this check here is useful -- cgit v1.2.3 From c389d27b5e643d745f55ffb939b1426060ba63d4 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 29 Jul 2008 22:33:32 -0700 Subject: 8250.c: port.lock is irq-safe serial8250_startup() doesn't disable interrupts while taking the &up->port.lock which might race against the interrupt handler serial8250_interrupt(), which when entered, will deadlock waiting for the lock to be released. Signed-off-by: Borislav Petkov Tested-by: Ingo Molnar Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/serial/8250.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index a97f1ae11f7..342e12fb1c2 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1885,7 +1885,7 @@ static int serial8250_startup(struct uart_port *port) * the interrupt is enabled. Delays are necessary to * allow register changes to become visible. */ - spin_lock(&up->port.lock); + spin_lock_irqsave(&up->port.lock, flags); if (up->port.flags & UPF_SHARE_IRQ) disable_irq_nosync(up->port.irq); @@ -1901,7 +1901,7 @@ static int serial8250_startup(struct uart_port *port) if (up->port.flags & UPF_SHARE_IRQ) enable_irq(up->port.irq); - spin_unlock(&up->port.lock); + spin_unlock_irqrestore(&up->port.lock, flags); /* * If the interrupt is not reasserted, setup a timer to -- cgit v1.2.3 From 8f3d137e0d6cd470a4e404cbc67480a0febdb0b1 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 29 Jul 2008 22:33:38 -0700 Subject: Char: mxser, ratelimit ioctl warning The GET_MAJOR ioctl prints out a warning, make it ratelimited. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/mxser.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index e30575e8764..b638403e8e9 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -1612,8 +1612,10 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) switch (cmd) { case MOXA_GET_MAJOR: - printk(KERN_WARNING "mxser: '%s' uses deprecated ioctl %x, fix " - "your userspace\n", current->comm, cmd); + if (printk_ratelimit()) + printk(KERN_WARNING "mxser: '%s' uses deprecated ioctl " + "%x (GET_MAJOR), fix your userspace\n", + current->comm, cmd); return put_user(ttymajor, (int __user *)argp); case MOXA_CHKPORTENABLE: -- cgit v1.2.3 From 836e4b14b41d19d17341a2dd2c49af8dd54e3aac Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 29 Jul 2008 22:33:43 -0700 Subject: USB: m66592-udc: Fix up dev_set_name() badness. Commit 0031a06e2f07ab0d1bc98c31dbb6801f95f4bf01 converted all of the USB drivers to use dev_set_name(), though there was a typo on the m66592-udc conversion that handed off the wrong pointer (we want the struct device here obviously, not the struct usb_gadget). Signed-off-by: Paul Mundt Cc: Kay Sievers Cc: Greg Kroah-Hartman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/gadget/m66592-udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 8da7535c0c7..77b44fb48f0 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1593,7 +1593,7 @@ static int __init m66592_probe(struct platform_device *pdev) m66592->gadget.ops = &m66592_gadget_ops; device_initialize(&m66592->gadget.dev); - dev_set_name(&m66592->gadget, "gadget"); + dev_set_name(&m66592->gadget.dev, "gadget"); m66592->gadget.is_dualspeed = 1; m66592->gadget.dev.parent = &pdev->dev; m66592->gadget.dev.dma_mask = pdev->dev.dma_mask; -- cgit v1.2.3 From 07a887d399b84668bc26cd040d699b26ec3086c2 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 29 Jul 2008 22:33:44 -0700 Subject: remove drivers/serial/v850e_uart.c The removal of drivers/serial/v850e_uart.c originally was in my v850 removal patch, but it seems it got lost somewhere. Reported-by: Robert P. J. Day Signed-off-by: Adrian Bunk Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/serial/Makefile | 1 - drivers/serial/v850e_uart.c | 548 -------------------------------------------- 2 files changed, 549 deletions(-) delete mode 100644 drivers/serial/v850e_uart.c (limited to 'drivers') diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 3a0bbbe17aa..7e7383e890d 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -42,7 +42,6 @@ obj-$(CONFIG_SERIAL_68328) += 68328serial.o obj-$(CONFIG_SERIAL_68360) += 68360serial.o obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o obj-$(CONFIG_SERIAL_MCF) += mcf.o -obj-$(CONFIG_V850E_UART) += v850e_uart.o obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o obj-$(CONFIG_SERIAL_DZ) += dz.o diff --git a/drivers/serial/v850e_uart.c b/drivers/serial/v850e_uart.c deleted file mode 100644 index 5acf061b6cd..00000000000 --- a/drivers/serial/v850e_uart.c +++ /dev/null @@ -1,548 +0,0 @@ -/* - * drivers/serial/v850e_uart.c -- Serial I/O using V850E on-chip UART or UARTB - * - * Copyright (C) 2001,02,03 NEC Electronics Corporation - * Copyright (C) 2001,02,03 Miles Bader - * - * 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. - * - * Written by Miles Bader - */ - -/* This driver supports both the original V850E UART interface (called - merely `UART' in the docs) and the newer `UARTB' interface, which is - roughly a superset of the first one. The selection is made at - configure time -- if CONFIG_V850E_UARTB is defined, then UARTB is - presumed, otherwise the old UART -- as these are on-CPU UARTS, a system - can never have both. - - The UARTB interface also has a 16-entry FIFO mode, which is not - yet supported by this driver. */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* Initial UART state. This may be overridden by machine-dependent headers. */ -#ifndef V850E_UART_INIT_BAUD -#define V850E_UART_INIT_BAUD 115200 -#endif -#ifndef V850E_UART_INIT_CFLAGS -#define V850E_UART_INIT_CFLAGS (B115200 | CS8 | CREAD) -#endif - -/* A string used for prefixing printed descriptions; since the same UART - macro is actually used on other chips than the V850E. This must be a - constant string. */ -#ifndef V850E_UART_CHIP_NAME -#define V850E_UART_CHIP_NAME "V850E" -#endif - -#define V850E_UART_MINOR_BASE 64 /* First tty minor number */ - - -/* Low-level UART functions. */ - -/* Configure and turn on uart channel CHAN, using the termios `control - modes' bits in CFLAGS, and a baud-rate of BAUD. */ -void v850e_uart_configure (unsigned chan, unsigned cflags, unsigned baud) -{ - int flags; - v850e_uart_speed_t old_speed; - v850e_uart_config_t old_config; - v850e_uart_speed_t new_speed = v850e_uart_calc_speed (baud); - v850e_uart_config_t new_config = v850e_uart_calc_config (cflags); - - /* Disable interrupts while we're twiddling the hardware. */ - local_irq_save (flags); - -#ifdef V850E_UART_PRE_CONFIGURE - V850E_UART_PRE_CONFIGURE (chan, cflags, baud); -#endif - - old_config = V850E_UART_CONFIG (chan); - old_speed = v850e_uart_speed (chan); - - if (! v850e_uart_speed_eq (old_speed, new_speed)) { - /* The baud rate has changed. First, disable the UART. */ - V850E_UART_CONFIG (chan) = V850E_UART_CONFIG_FINI; - old_config = 0; /* Force the uart to be re-initialized. */ - - /* Reprogram the baud-rate generator. */ - v850e_uart_set_speed (chan, new_speed); - } - - if (! (old_config & V850E_UART_CONFIG_ENABLED)) { - /* If we are using the uart for the first time, start by - enabling it, which must be done before turning on any - other bits. */ - V850E_UART_CONFIG (chan) = V850E_UART_CONFIG_INIT; - /* See the initial state. */ - old_config = V850E_UART_CONFIG (chan); - } - - if (new_config != old_config) { - /* Which of the TXE/RXE bits we'll temporarily turn off - before changing other control bits. */ - unsigned temp_disable = 0; - /* Which of the TXE/RXE bits will be enabled. */ - unsigned enable = 0; - unsigned changed_bits = new_config ^ old_config; - - /* Which of RX/TX will be enabled in the new configuration. */ - if (new_config & V850E_UART_CONFIG_RX_BITS) - enable |= (new_config & V850E_UART_CONFIG_RX_ENABLE); - if (new_config & V850E_UART_CONFIG_TX_BITS) - enable |= (new_config & V850E_UART_CONFIG_TX_ENABLE); - - /* Figure out which of RX/TX needs to be disabled; note - that this will only happen if they're not already - disabled. */ - if (changed_bits & V850E_UART_CONFIG_RX_BITS) - temp_disable - |= (old_config & V850E_UART_CONFIG_RX_ENABLE); - if (changed_bits & V850E_UART_CONFIG_TX_BITS) - temp_disable - |= (old_config & V850E_UART_CONFIG_TX_ENABLE); - - /* We have to turn off RX and/or TX mode before changing - any associated control bits. */ - if (temp_disable) - V850E_UART_CONFIG (chan) = old_config & ~temp_disable; - - /* Write the new control bits, while RX/TX are disabled. */ - if (changed_bits & ~enable) - V850E_UART_CONFIG (chan) = new_config & ~enable; - - v850e_uart_config_delay (new_config, new_speed); - - /* Write the final version, with enable bits turned on. */ - V850E_UART_CONFIG (chan) = new_config; - } - - local_irq_restore (flags); -} - - -/* Low-level console. */ - -#ifdef CONFIG_V850E_UART_CONSOLE - -static void v850e_uart_cons_write (struct console *co, - const char *s, unsigned count) -{ - if (count > 0) { - unsigned chan = co->index; - unsigned irq = V850E_UART_TX_IRQ (chan); - int irq_was_enabled, irq_was_pending, flags; - - /* We don't want to get `transmission completed' - interrupts, since we're busy-waiting, so we disable them - while sending (we don't disable interrupts entirely - because sending over a serial line is really slow). We - save the status of the tx interrupt and restore it when - we're done so that using printk doesn't interfere with - normal serial transmission (other than interleaving the - output, of course!). This should work correctly even if - this function is interrupted and the interrupt printks - something. */ - - /* Disable interrupts while fiddling with tx interrupt. */ - local_irq_save (flags); - /* Get current tx interrupt status. */ - irq_was_enabled = v850e_intc_irq_enabled (irq); - irq_was_pending = v850e_intc_irq_pending (irq); - /* Disable tx interrupt if necessary. */ - if (irq_was_enabled) - v850e_intc_disable_irq (irq); - /* Turn interrupts back on. */ - local_irq_restore (flags); - - /* Send characters. */ - while (count > 0) { - int ch = *s++; - - if (ch == '\n') { - /* We don't have the benefit of a tty - driver, so translate NL into CR LF. */ - v850e_uart_wait_for_xmit_ok (chan); - v850e_uart_putc (chan, '\r'); - } - - v850e_uart_wait_for_xmit_ok (chan); - v850e_uart_putc (chan, ch); - - count--; - } - - /* Restore saved tx interrupt status. */ - if (irq_was_enabled) { - /* Wait for the last character we sent to be - completely transmitted (as we'll get an - interrupt interrupt at that point). */ - v850e_uart_wait_for_xmit_done (chan); - /* Clear pending interrupts received due - to our transmission, unless there was already - one pending, in which case we want the - handler to be called. */ - if (! irq_was_pending) - v850e_intc_clear_pending_irq (irq); - /* ... and then turn back on handling. */ - v850e_intc_enable_irq (irq); - } - } -} - -extern struct uart_driver v850e_uart_driver; -static struct console v850e_uart_cons = -{ - .name = "ttyS", - .write = v850e_uart_cons_write, - .device = uart_console_device, - .flags = CON_PRINTBUFFER, - .cflag = V850E_UART_INIT_CFLAGS, - .index = -1, - .data = &v850e_uart_driver, -}; - -void v850e_uart_cons_init (unsigned chan) -{ - v850e_uart_configure (chan, V850E_UART_INIT_CFLAGS, - V850E_UART_INIT_BAUD); - v850e_uart_cons.index = chan; - register_console (&v850e_uart_cons); - printk ("Console: %s on-chip UART channel %d\n", - V850E_UART_CHIP_NAME, chan); -} - -/* This is what the init code actually calls. */ -static int v850e_uart_console_init (void) -{ - v850e_uart_cons_init (V850E_UART_CONSOLE_CHANNEL); - return 0; -} -console_initcall(v850e_uart_console_init); - -#define V850E_UART_CONSOLE &v850e_uart_cons - -#else /* !CONFIG_V850E_UART_CONSOLE */ -#define V850E_UART_CONSOLE 0 -#endif /* CONFIG_V850E_UART_CONSOLE */ - -/* TX/RX interrupt handlers. */ - -static void v850e_uart_stop_tx (struct uart_port *port); - -void v850e_uart_tx (struct uart_port *port) -{ - struct circ_buf *xmit = &port->info->xmit; - int stopped = uart_tx_stopped (port); - - if (v850e_uart_xmit_ok (port->line)) { - int tx_ch; - - if (port->x_char) { - tx_ch = port->x_char; - port->x_char = 0; - } else if (!uart_circ_empty (xmit) && !stopped) { - tx_ch = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } else - goto no_xmit; - - v850e_uart_putc (port->line, tx_ch); - port->icount.tx++; - - if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS) - uart_write_wakeup (port); - } - - no_xmit: - if (uart_circ_empty (xmit) || stopped) - v850e_uart_stop_tx (port, stopped); -} - -static irqreturn_t v850e_uart_tx_irq(int irq, void *data) -{ - struct uart_port *port = data; - v850e_uart_tx (port); - return IRQ_HANDLED; -} - -static irqreturn_t v850e_uart_rx_irq(int irq, void *data) -{ - struct uart_port *port = data; - unsigned ch_stat = TTY_NORMAL; - unsigned ch = v850e_uart_getc (port->line); - unsigned err = v850e_uart_err (port->line); - - if (err) { - if (err & V850E_UART_ERR_OVERRUN) { - ch_stat = TTY_OVERRUN; - port->icount.overrun++; - } else if (err & V850E_UART_ERR_FRAME) { - ch_stat = TTY_FRAME; - port->icount.frame++; - } else if (err & V850E_UART_ERR_PARITY) { - ch_stat = TTY_PARITY; - port->icount.parity++; - } - } - - port->icount.rx++; - - tty_insert_flip_char (port->info->port.tty, ch, ch_stat); - tty_schedule_flip (port->info->port.tty); - - return IRQ_HANDLED; -} - - -/* Control functions for the serial framework. */ - -static void v850e_uart_nop (struct uart_port *port) { } -static int v850e_uart_success (struct uart_port *port) { return 0; } - -static unsigned v850e_uart_tx_empty (struct uart_port *port) -{ - return TIOCSER_TEMT; /* Can't detect. */ -} - -static void v850e_uart_set_mctrl (struct uart_port *port, unsigned mctrl) -{ -#ifdef V850E_UART_SET_RTS - V850E_UART_SET_RTS (port->line, (mctrl & TIOCM_RTS)); -#endif -} - -static unsigned v850e_uart_get_mctrl (struct uart_port *port) -{ - /* We don't support DCD or DSR, so consider them permanently active. */ - int mctrl = TIOCM_CAR | TIOCM_DSR; - - /* We may support CTS. */ -#ifdef V850E_UART_CTS - mctrl |= V850E_UART_CTS(port->line) ? TIOCM_CTS : 0; -#else - mctrl |= TIOCM_CTS; -#endif - - return mctrl; -} - -static void v850e_uart_start_tx (struct uart_port *port) -{ - v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line)); - v850e_uart_tx (port); - v850e_intc_enable_irq (V850E_UART_TX_IRQ (port->line)); -} - -static void v850e_uart_stop_tx (struct uart_port *port) -{ - v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line)); -} - -static void v850e_uart_start_rx (struct uart_port *port) -{ - v850e_intc_enable_irq (V850E_UART_RX_IRQ (port->line)); -} - -static void v850e_uart_stop_rx (struct uart_port *port) -{ - v850e_intc_disable_irq (V850E_UART_RX_IRQ (port->line)); -} - -static void v850e_uart_break_ctl (struct uart_port *port, int break_ctl) -{ - /* Umm, do this later. */ -} - -static int v850e_uart_startup (struct uart_port *port) -{ - int err; - - /* Alloc RX irq. */ - err = request_irq (V850E_UART_RX_IRQ (port->line), v850e_uart_rx_irq, - IRQF_DISABLED, "v850e_uart", port); - if (err) - return err; - - /* Alloc TX irq. */ - err = request_irq (V850E_UART_TX_IRQ (port->line), v850e_uart_tx_irq, - IRQF_DISABLED, "v850e_uart", port); - if (err) { - free_irq (V850E_UART_RX_IRQ (port->line), port); - return err; - } - - v850e_uart_start_rx (port); - - return 0; -} - -static void v850e_uart_shutdown (struct uart_port *port) -{ - /* Disable port interrupts. */ - free_irq (V850E_UART_TX_IRQ (port->line), port); - free_irq (V850E_UART_RX_IRQ (port->line), port); - - /* Turn off xmit/recv enable bits. */ - V850E_UART_CONFIG (port->line) - &= ~(V850E_UART_CONFIG_TX_ENABLE - | V850E_UART_CONFIG_RX_ENABLE); - /* Then reset the channel. */ - V850E_UART_CONFIG (port->line) = 0; -} - -static void -v850e_uart_set_termios (struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - unsigned cflags = termios->c_cflag; - - /* Restrict flags to legal values. */ - if ((cflags & CSIZE) != CS7 && (cflags & CSIZE) != CS8) - /* The new value of CSIZE is invalid, use the old value. */ - cflags = (cflags & ~CSIZE) - | (old ? (old->c_cflag & CSIZE) : CS8); - - termios->c_cflag = cflags; - - v850e_uart_configure (port->line, cflags, - uart_get_baud_rate (port, termios, old, - v850e_uart_min_baud(), - v850e_uart_max_baud())); -} - -static const char *v850e_uart_type (struct uart_port *port) -{ - return port->type == PORT_V850E_UART ? "v850e_uart" : 0; -} - -static void v850e_uart_config_port (struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) - port->type = PORT_V850E_UART; -} - -static int -v850e_uart_verify_port (struct uart_port *port, struct serial_struct *ser) -{ - if (ser->type != PORT_UNKNOWN && ser->type != PORT_V850E_UART) - return -EINVAL; - if (ser->irq != V850E_UART_TX_IRQ (port->line)) - return -EINVAL; - return 0; -} - -static struct uart_ops v850e_uart_ops = { - .tx_empty = v850e_uart_tx_empty, - .get_mctrl = v850e_uart_get_mctrl, - .set_mctrl = v850e_uart_set_mctrl, - .start_tx = v850e_uart_start_tx, - .stop_tx = v850e_uart_stop_tx, - .stop_rx = v850e_uart_stop_rx, - .enable_ms = v850e_uart_nop, - .break_ctl = v850e_uart_break_ctl, - .startup = v850e_uart_startup, - .shutdown = v850e_uart_shutdown, - .set_termios = v850e_uart_set_termios, - .type = v850e_uart_type, - .release_port = v850e_uart_nop, - .request_port = v850e_uart_success, - .config_port = v850e_uart_config_port, - .verify_port = v850e_uart_verify_port, -}; - -/* Initialization and cleanup. */ - -static struct uart_driver v850e_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "v850e_uart", - .dev_name = "ttyS", - .major = TTY_MAJOR, - .minor = V850E_UART_MINOR_BASE, - .nr = V850E_UART_NUM_CHANNELS, - .cons = V850E_UART_CONSOLE, -}; - - -static struct uart_port v850e_uart_ports[V850E_UART_NUM_CHANNELS]; - -static int __init v850e_uart_init (void) -{ - int rval; - - printk (KERN_INFO "%s on-chip UART\n", V850E_UART_CHIP_NAME); - - rval = uart_register_driver (&v850e_uart_driver); - if (rval == 0) { - unsigned chan; - - for (chan = 0; chan < V850E_UART_NUM_CHANNELS; chan++) { - struct uart_port *port = &v850e_uart_ports[chan]; - - memset (port, 0, sizeof *port); - - port->ops = &v850e_uart_ops; - port->line = chan; - port->iotype = UPIO_MEM; - port->flags = UPF_BOOT_AUTOCONF; - - /* We actually use multiple IRQs, but the serial - framework seems to mainly use this for - informational purposes anyway. Here we use the TX - irq. */ - port->irq = V850E_UART_TX_IRQ (chan); - - /* The serial framework doesn't really use these - membase/mapbase fields for anything useful, but - it requires that they be something non-zero to - consider the port `valid', and also uses them - for informational purposes. */ - port->membase = (void *)V850E_UART_BASE_ADDR (chan); - port->mapbase = V850E_UART_BASE_ADDR (chan); - - /* The framework insists on knowing the uart's master - clock freq, though it doesn't seem to do anything - useful for us with it. We must make it at least - higher than (the maximum baud rate * 16), otherwise - the framework will puke during its internal - calculations, and force the baud rate to be 9600. - To be accurate though, just repeat the calculation - we use when actually setting the speed. */ - port->uartclk = v850e_uart_max_clock() * 16; - - uart_add_one_port (&v850e_uart_driver, port); - } - } - - return rval; -} - -static void __exit v850e_uart_exit (void) -{ - unsigned chan; - - for (chan = 0; chan < V850E_UART_NUM_CHANNELS; chan++) - uart_remove_one_port (&v850e_uart_driver, - &v850e_uart_ports[chan]); - - uart_unregister_driver (&v850e_uart_driver); -} - -module_init (v850e_uart_init); -module_exit (v850e_uart_exit); - -MODULE_AUTHOR ("Miles Bader"); -MODULE_DESCRIPTION ("NEC " V850E_UART_CHIP_NAME " on-chip UART"); -MODULE_LICENSE ("GPL"); -- cgit v1.2.3 From 8d0b1c51eb8375f88c0886d2e9f71881e19d42a7 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Tue, 29 Jul 2008 22:33:49 -0700 Subject: gbefb: cmap FIFO timeout Writes to the cmap fifo while the display is blanked caused cmap FIFO timeout messages and a wrong colormap. To avoid this the driver now maintains a colormap in memory and updates the colormap after the display is unblanked. Signed-off-by: Thomas Bogendoerfer Cc: Krzysztof Helt Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/gbefb.c | 50 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index 2e552d5bbb5..f89c3cce1e0 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -87,6 +87,8 @@ static int gbe_revision; static int ypan, ywrap; static uint32_t pseudo_palette[16]; +static uint32_t gbe_cmap[256]; +static int gbe_turned_on; /* 0 turned off, 1 turned on */ static char *mode_option __initdata = NULL; @@ -208,6 +210,8 @@ void gbe_turn_off(void) int i; unsigned int val, x, y, vpixen_off; + gbe_turned_on = 0; + /* check if pixel counter is on */ val = gbe->vt_xy; if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 1) @@ -371,6 +375,22 @@ static void gbe_turn_on(void) } if (i == 10000) printk(KERN_ERR "gbefb: turn on DMA timed out\n"); + + gbe_turned_on = 1; +} + +static void gbe_loadcmap(void) +{ + int i, j; + + for (i = 0; i < 256; i++) { + for (j = 0; j < 1000 && gbe->cm_fifo >= 63; j++) + udelay(10); + if (j == 1000) + printk(KERN_ERR "gbefb: cmap FIFO timeout\n"); + + gbe->cmap[i] = gbe_cmap[i]; + } } /* @@ -382,6 +402,7 @@ static int gbefb_blank(int blank, struct fb_info *info) switch (blank) { case FB_BLANK_UNBLANK: /* unblank */ gbe_turn_on(); + gbe_loadcmap(); break; case FB_BLANK_NORMAL: /* blank */ @@ -796,16 +817,10 @@ static int gbefb_set_par(struct fb_info *info) gbe->gmap[i] = (i << 24) | (i << 16) | (i << 8); /* Initialize the color map */ - for (i = 0; i < 256; i++) { - int j; - - for (j = 0; j < 1000 && gbe->cm_fifo >= 63; j++) - udelay(10); - if (j == 1000) - printk(KERN_ERR "gbefb: cmap FIFO timeout\n"); + for (i = 0; i < 256; i++) + gbe_cmap[i] = (i << 8) | (i << 16) | (i << 24); - gbe->cmap[i] = (i << 8) | (i << 16) | (i << 24); - } + gbe_loadcmap(); return 0; } @@ -855,14 +870,17 @@ static int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green, blue >>= 8; if (info->var.bits_per_pixel <= 8) { - /* wait for the color map FIFO to have a free entry */ - for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++) - udelay(10); - if (i == 1000) { - printk(KERN_ERR "gbefb: cmap FIFO timeout\n"); - return 1; + gbe_cmap[regno] = (red << 24) | (green << 16) | (blue << 8); + if (gbe_turned_on) { + /* wait for the color map FIFO to have a free entry */ + for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++) + udelay(10); + if (i == 1000) { + printk(KERN_ERR "gbefb: cmap FIFO timeout\n"); + return 1; + } + gbe->cmap[regno] = gbe_cmap[regno]; } - gbe->cmap[regno] = (red << 24) | (green << 16) | (blue << 8); } else if (regno < 16) { switch (info->var.bits_per_pixel) { case 15: -- cgit v1.2.3 From 5cdc98b8f51310f7cca05ad780f18f80dd9571de Mon Sep 17 00:00:00 2001 From: Tomas Janousek Date: Tue, 29 Jul 2008 22:33:51 -0700 Subject: rtc-dev: stop periodic interrupts on device release Solves http://bugzilla.kernel.org/show_bug.cgi?id=11127 The old rtc.c driver did it and some drivers (like rtc-sh) do it in their release function, though they should not -- because they should provide the irq_set_state op and the rtc framework itself should care about it. This patch makes it do so. I am aware that some drivers, like rtc-sh, handle userspace PIE sets in their ioctl op (instead of having the framework call the op), exporting the irq_set_state op at the same time. The logic in rtc_irq_set_state should make sure it doesn't matter and the driver should not need to care stopping periodic interrupts in its release routine any more. The correct way, in my opinion, should be this: 1) The driver provides the irq_set_state op and does not care closing the interrupts in its release op. 2) If the driver does not provide the op and handles PIE in the ioctl op, it's reponsible for closing them in its release op. 3) Something similar for other IRQs, like UIE -- if there's no in-kernel API like irq_set_state, handle it in ioctl and release ops. The framework will be responsible either for everything or for nothing. (This will probably change later.) Signed-off-by: Tomas Janousek Acked-by: David Brownell Acked-by: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-dev.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index ae3bd4de767..856cc1af40d 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -432,6 +432,8 @@ static int rtc_dev_release(struct inode *inode, struct file *file) #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL clear_uie(rtc); #endif + rtc_irq_set_state(rtc, NULL, 0); + if (rtc->ops->release) rtc->ops->release(rtc->dev.parent); -- cgit v1.2.3 From 34d8a380d784d1fbea941a68beebdd7f9a3bebdf Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Tue, 29 Jul 2008 22:33:54 -0700 Subject: GRU Driver: hardware data structures This series of patches adds a driver for the SGI UV GRU. The driver is still in development but it currently compiles for both x86_64 & IA64. All simple regression tests pass on IA64. Although features remain to be added, I'd like to start the process of getting the driver into the kernel. Additional kernel drivers will depend on services provide by the GRU driver. The GRU is a hardware resource located in the system chipset. The GRU contains memory that is mmaped into the user address space. This memory is used to communicate with the GRU to perform functions such as load/store, scatter/gather, bcopy, AMOs, etc. The GRU is directly accessed by user instructions using user virtual addresses. GRU instructions (ex., bcopy) use user virtual addresses for operands. The GRU contains a large TLB that is functionally very similar to processor TLBs. Because the external contains a TLB with user virtual address, it requires callouts from the core VM system when certain types of changes are made to the process page tables. There are several MMUOPS patches currently being discussed but none has been accepted into the kernel. The GRU driver is built using version V18 from Andrea Arcangeli. This patch: Contains the definitions of the hardware GRU data structures that are used by the driver to manage the GRU. [akpm@linux-foundation;org: export hpage_shift] Signed-off-by: Jack Steiner Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-gru/gruhandles.h | 663 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 663 insertions(+) create mode 100644 drivers/misc/sgi-gru/gruhandles.h (limited to 'drivers') diff --git a/drivers/misc/sgi-gru/gruhandles.h b/drivers/misc/sgi-gru/gruhandles.h new file mode 100644 index 00000000000..d16031d6267 --- /dev/null +++ b/drivers/misc/sgi-gru/gruhandles.h @@ -0,0 +1,663 @@ +/* + * SN Platform GRU Driver + * + * GRU HANDLE DEFINITION + * + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __GRUHANDLES_H__ +#define __GRUHANDLES_H__ +#include "gru_instructions.h" + +/* + * Manifest constants for GRU Memory Map + */ +#define GRU_GSEG0_BASE 0 +#define GRU_MCS_BASE (64 * 1024 * 1024) +#define GRU_SIZE (128UL * 1024 * 1024) + +/* Handle & resource counts */ +#define GRU_NUM_CB 128 +#define GRU_NUM_DSR_BYTES (32 * 1024) +#define GRU_NUM_TFM 16 +#define GRU_NUM_TGH 24 +#define GRU_NUM_CBE 128 +#define GRU_NUM_TFH 128 +#define GRU_NUM_CCH 16 +#define GRU_NUM_GSH 1 + +/* Maximum resource counts that can be reserved by user programs */ +#define GRU_NUM_USER_CBR GRU_NUM_CBE +#define GRU_NUM_USER_DSR_BYTES GRU_NUM_DSR_BYTES + +/* Bytes per handle & handle stride. Code assumes all cb, tfh, cbe handles + * are the same */ +#define GRU_HANDLE_BYTES 64 +#define GRU_HANDLE_STRIDE 256 + +/* Base addresses of handles */ +#define GRU_TFM_BASE (GRU_MCS_BASE + 0x00000) +#define GRU_TGH_BASE (GRU_MCS_BASE + 0x08000) +#define GRU_CBE_BASE (GRU_MCS_BASE + 0x10000) +#define GRU_TFH_BASE (GRU_MCS_BASE + 0x18000) +#define GRU_CCH_BASE (GRU_MCS_BASE + 0x20000) +#define GRU_GSH_BASE (GRU_MCS_BASE + 0x30000) + +/* User gseg constants */ +#define GRU_GSEG_STRIDE (4 * 1024 * 1024) +#define GSEG_BASE(a) ((a) & ~(GRU_GSEG_PAGESIZE - 1)) + +/* Data segment constants */ +#define GRU_DSR_AU_BYTES 1024 +#define GRU_DSR_CL (GRU_NUM_DSR_BYTES / GRU_CACHE_LINE_BYTES) +#define GRU_DSR_AU_CL (GRU_DSR_AU_BYTES / GRU_CACHE_LINE_BYTES) +#define GRU_DSR_AU (GRU_NUM_DSR_BYTES / GRU_DSR_AU_BYTES) + +/* Control block constants */ +#define GRU_CBR_AU_SIZE 2 +#define GRU_CBR_AU (GRU_NUM_CBE / GRU_CBR_AU_SIZE) + +/* Convert resource counts to the number of AU */ +#define GRU_DS_BYTES_TO_AU(n) DIV_ROUND_UP(n, GRU_DSR_AU_BYTES) +#define GRU_CB_COUNT_TO_AU(n) DIV_ROUND_UP(n, GRU_CBR_AU_SIZE) + +/* UV limits */ +#define GRU_CHIPLETS_PER_HUB 2 +#define GRU_HUBS_PER_BLADE 1 +#define GRU_CHIPLETS_PER_BLADE (GRU_HUBS_PER_BLADE * GRU_CHIPLETS_PER_HUB) + +/* User GRU Gseg offsets */ +#define GRU_CB_BASE 0 +#define GRU_CB_LIMIT (GRU_CB_BASE + GRU_HANDLE_STRIDE * GRU_NUM_CBE) +#define GRU_DS_BASE 0x20000 +#define GRU_DS_LIMIT (GRU_DS_BASE + GRU_NUM_DSR_BYTES) + +/* Convert a GRU physical address to the chiplet offset */ +#define GSEGPOFF(h) ((h) & (GRU_SIZE - 1)) + +/* Convert an arbitrary handle address to the beginning of the GRU segment */ +#ifndef __PLUGIN__ +#define GRUBASE(h) ((void *)((unsigned long)(h) & ~(GRU_SIZE - 1))) +#else +extern void *gmu_grubase(void *h); +#define GRUBASE(h) gmu_grubase(h) +#endif + +/* General addressing macros. */ +static inline void *get_gseg_base_address(void *base, int ctxnum) +{ + return (void *)(base + GRU_GSEG0_BASE + GRU_GSEG_STRIDE * ctxnum); +} + +static inline void *get_gseg_base_address_cb(void *base, int ctxnum, int line) +{ + return (void *)(get_gseg_base_address(base, ctxnum) + + GRU_CB_BASE + GRU_HANDLE_STRIDE * line); +} + +static inline void *get_gseg_base_address_ds(void *base, int ctxnum, int line) +{ + return (void *)(get_gseg_base_address(base, ctxnum) + GRU_DS_BASE + + GRU_CACHE_LINE_BYTES * line); +} + +static inline struct gru_tlb_fault_map *get_tfm(void *base, int ctxnum) +{ + return (struct gru_tlb_fault_map *)(base + GRU_TFM_BASE + + ctxnum * GRU_HANDLE_STRIDE); +} + +static inline struct gru_tlb_global_handle *get_tgh(void *base, int ctxnum) +{ + return (struct gru_tlb_global_handle *)(base + GRU_TGH_BASE + + ctxnum * GRU_HANDLE_STRIDE); +} + +static inline struct gru_control_block_extended *get_cbe(void *base, int ctxnum) +{ + return (struct gru_control_block_extended *)(base + GRU_CBE_BASE + + ctxnum * GRU_HANDLE_STRIDE); +} + +static inline struct gru_tlb_fault_handle *get_tfh(void *base, int ctxnum) +{ + return (struct gru_tlb_fault_handle *)(base + GRU_TFH_BASE + + ctxnum * GRU_HANDLE_STRIDE); +} + +static inline struct gru_context_configuration_handle *get_cch(void *base, + int ctxnum) +{ + return (struct gru_context_configuration_handle *)(base + + GRU_CCH_BASE + ctxnum * GRU_HANDLE_STRIDE); +} + +static inline unsigned long get_cb_number(void *cb) +{ + return (((unsigned long)cb - GRU_CB_BASE) % GRU_GSEG_PAGESIZE) / + GRU_HANDLE_STRIDE; +} + +/* byte offset to a specific GRU chiplet. (p=pnode, c=chiplet (0 or 1)*/ +static inline unsigned long gru_chiplet_paddr(unsigned long paddr, int pnode, + int chiplet) +{ + return paddr + GRU_SIZE * (2 * pnode + chiplet); +} + +static inline void *gru_chiplet_vaddr(void *vaddr, int pnode, int chiplet) +{ + return vaddr + GRU_SIZE * (2 * pnode + chiplet); +} + + + +/* + * Global TLB Fault Map + * Bitmap of outstanding TLB misses needing interrupt/polling service. + * + */ +struct gru_tlb_fault_map { + unsigned long fault_bits[BITS_TO_LONGS(GRU_NUM_CBE)]; + unsigned long fill0[2]; + unsigned long done_bits[BITS_TO_LONGS(GRU_NUM_CBE)]; + unsigned long fill1[2]; +}; + +/* + * TGH - TLB Global Handle + * Used for TLB flushing. + * + */ +struct gru_tlb_global_handle { + unsigned int cmd:1; /* DW 0 */ + unsigned int delresp:1; + unsigned int opc:1; + unsigned int fill1:5; + + unsigned int fill2:8; + + unsigned int status:2; + unsigned long fill3:2; + unsigned int state:3; + unsigned long fill4:1; + + unsigned int cause:3; + unsigned long fill5:37; + + unsigned long vaddr:64; /* DW 1 */ + + unsigned int asid:24; /* DW 2 */ + unsigned int fill6:8; + + unsigned int pagesize:5; + unsigned int fill7:11; + + unsigned int global:1; + unsigned int fill8:15; + + unsigned long vaddrmask:39; /* DW 3 */ + unsigned int fill9:9; + unsigned int n:10; + unsigned int fill10:6; + + unsigned int ctxbitmap:16; /* DW4 */ + unsigned long fill11[3]; +}; + +enum gru_tgh_cmd { + TGHCMD_START +}; + +enum gru_tgh_opc { + TGHOP_TLBNOP, + TGHOP_TLBINV +}; + +enum gru_tgh_status { + TGHSTATUS_IDLE, + TGHSTATUS_EXCEPTION, + TGHSTATUS_ACTIVE +}; + +enum gru_tgh_state { + TGHSTATE_IDLE, + TGHSTATE_PE_INVAL, + TGHSTATE_INTERRUPT_INVAL, + TGHSTATE_WAITDONE, + TGHSTATE_RESTART_CTX, +}; + +/* + * TFH - TLB Global Handle + * Used for TLB dropins into the GRU TLB. + * + */ +struct gru_tlb_fault_handle { + unsigned int cmd:1; /* DW 0 - low 32*/ + unsigned int delresp:1; + unsigned int fill0:2; + unsigned int opc:3; + unsigned int fill1:9; + + unsigned int status:2; + unsigned int fill2:1; + unsigned int color:1; + unsigned int state:3; + unsigned int fill3:1; + + unsigned int cause:7; /* DW 0 - high 32 */ + unsigned int fill4:1; + + unsigned int indexway:12; + unsigned int fill5:4; + + unsigned int ctxnum:4; + unsigned int fill6:12; + + unsigned long missvaddr:64; /* DW 1 */ + + unsigned int missasid:24; /* DW 2 */ + unsigned int fill7:8; + unsigned int fillasid:24; + unsigned int dirty:1; + unsigned int gaa:2; + unsigned long fill8:5; + + unsigned long pfn:41; /* DW 3 */ + unsigned int fill9:7; + unsigned int pagesize:5; + unsigned int fill10:11; + + unsigned long fillvaddr:64; /* DW 4 */ + + unsigned long fill11[3]; +}; + +enum gru_tfh_opc { + TFHOP_NOOP, + TFHOP_RESTART, + TFHOP_WRITE_ONLY, + TFHOP_WRITE_RESTART, + TFHOP_EXCEPTION, + TFHOP_USER_POLLING_MODE = 7, +}; + +enum tfh_status { + TFHSTATUS_IDLE, + TFHSTATUS_EXCEPTION, + TFHSTATUS_ACTIVE, +}; + +enum tfh_state { + TFHSTATE_INACTIVE, + TFHSTATE_IDLE, + TFHSTATE_MISS_UPM, + TFHSTATE_MISS_FMM, + TFHSTATE_HW_ERR, + TFHSTATE_WRITE_TLB, + TFHSTATE_RESTART_CBR, +}; + +/* TFH cause bits */ +enum tfh_cause { + TFHCAUSE_NONE, + TFHCAUSE_TLB_MISS, + TFHCAUSE_TLB_MOD, + TFHCAUSE_HW_ERROR_RR, + TFHCAUSE_HW_ERROR_MAIN_ARRAY, + TFHCAUSE_HW_ERROR_VALID, + TFHCAUSE_HW_ERROR_PAGESIZE, + TFHCAUSE_INSTRUCTION_EXCEPTION, + TFHCAUSE_UNCORRECTIBLE_ERROR, +}; + +/* GAA values */ +#define GAA_RAM 0x0 +#define GAA_NCRAM 0x2 +#define GAA_MMIO 0x1 +#define GAA_REGISTER 0x3 + +/* GRU paddr shift for pfn. (NOTE: shift is NOT by actual pagesize) */ +#define GRU_PADDR_SHIFT 12 + +/* + * Context Configuration handle + * Used to allocate resources to a GSEG context. + * + */ +struct gru_context_configuration_handle { + unsigned int cmd:1; /* DW0 */ + unsigned int delresp:1; + unsigned int opc:3; + unsigned int unmap_enable:1; + unsigned int req_slice_set_enable:1; + unsigned int req_slice:2; + unsigned int cb_int_enable:1; + unsigned int tlb_int_enable:1; + unsigned int tfm_fault_bit_enable:1; + unsigned int tlb_int_select:4; + + unsigned int status:2; + unsigned int state:2; + unsigned int reserved2:4; + + unsigned int cause:4; + unsigned int tfm_done_bit_enable:1; + unsigned int unused:3; + + unsigned int dsr_allocation_map; + + unsigned long cbr_allocation_map; /* DW1 */ + + unsigned int asid[8]; /* DW 2 - 5 */ + unsigned short sizeavail[8]; /* DW 6 - 7 */ +} __attribute__ ((packed)); + +enum gru_cch_opc { + CCHOP_START = 1, + CCHOP_ALLOCATE, + CCHOP_INTERRUPT, + CCHOP_DEALLOCATE, + CCHOP_INTERRUPT_SYNC, +}; + +enum gru_cch_status { + CCHSTATUS_IDLE, + CCHSTATUS_EXCEPTION, + CCHSTATUS_ACTIVE, +}; + +enum gru_cch_state { + CCHSTATE_INACTIVE, + CCHSTATE_MAPPED, + CCHSTATE_ACTIVE, + CCHSTATE_INTERRUPTED, +}; + +/* CCH Exception cause */ +enum gru_cch_cause { + CCHCAUSE_REGION_REGISTER_WRITE_ERROR = 1, + CCHCAUSE_ILLEGAL_OPCODE = 2, + CCHCAUSE_INVALID_START_REQUEST = 3, + CCHCAUSE_INVALID_ALLOCATION_REQUEST = 4, + CCHCAUSE_INVALID_DEALLOCATION_REQUEST = 5, + CCHCAUSE_INVALID_INTERRUPT_REQUEST = 6, + CCHCAUSE_CCH_BUSY = 7, + CCHCAUSE_NO_CBRS_TO_ALLOCATE = 8, + CCHCAUSE_BAD_TFM_CONFIG = 9, + CCHCAUSE_CBR_RESOURCES_OVERSUBSCRIPED = 10, + CCHCAUSE_DSR_RESOURCES_OVERSUBSCRIPED = 11, + CCHCAUSE_CBR_DEALLOCATION_ERROR = 12, +}; +/* + * CBE - Control Block Extended + * Maintains internal GRU state for active CBs. + * + */ +struct gru_control_block_extended { + unsigned int reserved0:1; /* DW 0 - low */ + unsigned int imacpy:3; + unsigned int reserved1:4; + unsigned int xtypecpy:3; + unsigned int iaa0cpy:2; + unsigned int iaa1cpy:2; + unsigned int reserved2:1; + unsigned int opccpy:8; + unsigned int exopccpy:8; + + unsigned int idef2cpy:22; /* DW 0 - high */ + unsigned int reserved3:10; + + unsigned int idef4cpy:22; /* DW 1 */ + unsigned int reserved4:10; + unsigned int idef4upd:22; + unsigned int reserved5:10; + + unsigned long idef1upd:64; /* DW 2 */ + + unsigned long idef5cpy:64; /* DW 3 */ + + unsigned long idef6cpy:64; /* DW 4 */ + + unsigned long idef3upd:64; /* DW 5 */ + + unsigned long idef5upd:64; /* DW 6 */ + + unsigned int idef2upd:22; /* DW 7 */ + unsigned int reserved6:10; + + unsigned int ecause:20; + unsigned int cbrstate:4; + unsigned int cbrexecstatus:8; +}; + +enum gru_cbr_state { + CBRSTATE_INACTIVE, + CBRSTATE_IDLE, + CBRSTATE_PE_CHECK, + CBRSTATE_QUEUED, + CBRSTATE_WAIT_RESPONSE, + CBRSTATE_INTERRUPTED, + CBRSTATE_INTERRUPTED_MISS_FMM, + CBRSTATE_BUSY_INTERRUPT_MISS_FMM, + CBRSTATE_INTERRUPTED_MISS_UPM, + CBRSTATE_BUSY_INTERRUPTED_MISS_UPM, + CBRSTATE_REQUEST_ISSUE, + CBRSTATE_BUSY_INTERRUPT, +}; + +/* CBE cbrexecstatus bits */ +#define CBR_EXS_ABORT_OCC_BIT 0 +#define CBR_EXS_INT_OCC_BIT 1 +#define CBR_EXS_PENDING_BIT 2 +#define CBR_EXS_QUEUED_BIT 3 +#define CBR_EXS_TLBHW_BIT 4 +#define CBR_EXS_EXCEPTION_BIT 5 + +#define CBR_EXS_ABORT_OCC (1 << CBR_EXS_ABORT_OCC_BIT) +#define CBR_EXS_INT_OCC (1 << CBR_EXS_INT_OCC_BIT) +#define CBR_EXS_PENDING (1 << CBR_EXS_PENDING_BIT) +#define CBR_EXS_QUEUED (1 << CBR_EXS_QUEUED_BIT) +#define CBR_EXS_TLBHW (1 << CBR_EXS_TLBHW_BIT) +#define CBR_EXS_EXCEPTION (1 << CBR_EXS_EXCEPTION_BIT) + +/* CBE ecause bits - defined in gru_instructions.h */ + +/* + * Convert a processor pagesize into the strange encoded pagesize used by the + * GRU. Processor pagesize is encoded as log of bytes per page. (or PAGE_SHIFT) + * pagesize log pagesize grupagesize + * 4k 12 0 + * 16k 14 1 + * 64k 16 2 + * 256k 18 3 + * 1m 20 4 + * 2m 21 5 + * 4m 22 6 + * 16m 24 7 + * 64m 26 8 + * ... + */ +#define GRU_PAGESIZE(sh) ((((sh) > 20 ? (sh) + 2: (sh)) >> 1) - 6) +#define GRU_SIZEAVAIL(sh) (1UL << GRU_PAGESIZE(sh)) + +/* minimum TLB purge count to ensure a full purge */ +#define GRUMAXINVAL 1024UL + + +/* Extract the status field from a kernel handle */ +#define GET_MSEG_HANDLE_STATUS(h) (((*(unsigned long *)(h)) >> 16) & 3) + +static inline void start_instruction(void *h) +{ + unsigned long *w0 = h; + + wmb(); /* setting CMD bit must be last */ + *w0 = *w0 | 1; + gru_flush_cache(h); +} + +static inline int wait_instruction_complete(void *h) +{ + int status; + + do { + cpu_relax(); + barrier(); + status = GET_MSEG_HANDLE_STATUS(h); + } while (status == CCHSTATUS_ACTIVE); + return status; +} + +#if defined CONFIG_IA64 +static inline void cch_allocate_set_asids( + struct gru_context_configuration_handle *cch, int asidval) +{ + int i; + + for (i = 0; i <= RGN_HPAGE; i++) { /* assume HPAGE is last region */ + cch->asid[i] = (asidval++); +#if 0 + /* ZZZ hugepages not supported yet */ + if (i == RGN_HPAGE) + cch->sizeavail[i] = GRU_SIZEAVAIL(hpage_shift); + else +#endif + cch->sizeavail[i] = GRU_SIZEAVAIL(PAGE_SHIFT); + } +} +#elif defined CONFIG_X86_64 +static inline void cch_allocate_set_asids( + struct gru_context_configuration_handle *cch, int asidval) +{ + int i; + + for (i = 0; i < 8; i++) { + cch->asid[i] = asidval++; + cch->sizeavail[i] = GRU_SIZEAVAIL(PAGE_SHIFT) | + GRU_SIZEAVAIL(21); + } +} +#endif + +static inline int cch_allocate(struct gru_context_configuration_handle *cch, + int asidval, unsigned long cbrmap, + unsigned long dsrmap) +{ + cch_allocate_set_asids(cch, asidval); + cch->dsr_allocation_map = dsrmap; + cch->cbr_allocation_map = cbrmap; + cch->opc = CCHOP_ALLOCATE; + start_instruction(cch); + return wait_instruction_complete(cch); +} + +static inline int cch_start(struct gru_context_configuration_handle *cch) +{ + cch->opc = CCHOP_START; + start_instruction(cch); + return wait_instruction_complete(cch); +} + +static inline int cch_interrupt(struct gru_context_configuration_handle *cch) +{ + cch->opc = CCHOP_INTERRUPT; + start_instruction(cch); + return wait_instruction_complete(cch); +} + +static inline int cch_deallocate(struct gru_context_configuration_handle *cch) +{ + cch->opc = CCHOP_DEALLOCATE; + start_instruction(cch); + return wait_instruction_complete(cch); +} + +static inline int cch_interrupt_sync(struct gru_context_configuration_handle + *cch) +{ + cch->opc = CCHOP_INTERRUPT_SYNC; + start_instruction(cch); + return wait_instruction_complete(cch); +} + +static inline int tgh_invalidate(struct gru_tlb_global_handle *tgh, + unsigned long vaddr, unsigned long vaddrmask, + int asid, int pagesize, int global, int n, + unsigned short ctxbitmap) +{ + tgh->vaddr = vaddr; + tgh->asid = asid; + tgh->pagesize = pagesize; + tgh->n = n; + tgh->global = global; + tgh->vaddrmask = vaddrmask; + tgh->ctxbitmap = ctxbitmap; + tgh->opc = TGHOP_TLBINV; + start_instruction(tgh); + return wait_instruction_complete(tgh); +} + +static inline void tfh_write_only(struct gru_tlb_fault_handle *tfh, + unsigned long pfn, unsigned long vaddr, + int asid, int dirty, int pagesize) +{ + tfh->fillasid = asid; + tfh->fillvaddr = vaddr; + tfh->pfn = pfn; + tfh->dirty = dirty; + tfh->pagesize = pagesize; + tfh->opc = TFHOP_WRITE_ONLY; + start_instruction(tfh); +} + +static inline void tfh_write_restart(struct gru_tlb_fault_handle *tfh, + unsigned long paddr, int gaa, + unsigned long vaddr, int asid, int dirty, + int pagesize) +{ + tfh->fillasid = asid; + tfh->fillvaddr = vaddr; + tfh->pfn = paddr >> GRU_PADDR_SHIFT; + tfh->gaa = gaa; + tfh->dirty = dirty; + tfh->pagesize = pagesize; + tfh->opc = TFHOP_WRITE_RESTART; + start_instruction(tfh); +} + +static inline void tfh_restart(struct gru_tlb_fault_handle *tfh) +{ + tfh->opc = TFHOP_RESTART; + start_instruction(tfh); +} + +static inline void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh) +{ + tfh->opc = TFHOP_USER_POLLING_MODE; + start_instruction(tfh); +} + +static inline void tfh_exception(struct gru_tlb_fault_handle *tfh) +{ + tfh->opc = TFHOP_EXCEPTION; + start_instruction(tfh); +} + +#endif /* __GRUHANDLES_H__ */ -- cgit v1.2.3 From 4c921d4d8aa74140597fd8736261837f73ca6e7a Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Tue, 29 Jul 2008 22:33:54 -0700 Subject: GRU Driver: GRU instructions & macros This patchs contains macros & inline functions used to issue instructions to the GRU. Signed-off-by: Jack Steiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-gru/gru_instructions.h | 679 ++++++++++++++++++++++++++++++++ 1 file changed, 679 insertions(+) create mode 100644 drivers/misc/sgi-gru/gru_instructions.h (limited to 'drivers') diff --git a/drivers/misc/sgi-gru/gru_instructions.h b/drivers/misc/sgi-gru/gru_instructions.h new file mode 100644 index 00000000000..3159b261c5a --- /dev/null +++ b/drivers/misc/sgi-gru/gru_instructions.h @@ -0,0 +1,679 @@ +/* + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __GRU_INSTRUCTIONS_H__ +#define __GRU_INSTRUCTIONS_H__ + +#define gru_flush_cache_hook(p) +#define gru_emulator_wait_hook(p, w) + +/* + * Architecture dependent functions + */ + +#if defined CONFIG_IA64 +#include +#include +#define __flush_cache(p) ia64_fc(p) +/* Use volatile on IA64 to ensure ordering via st4.rel */ +#define gru_ordered_store_int(p,v) \ + do { \ + barrier(); \ + *((volatile int *)(p)) = v; /* force st.rel */ \ + } while (0) +#elif defined CONFIG_X86_64 +#define __flush_cache(p) clflush(p) +#define gru_ordered_store_int(p,v) \ + do { \ + barrier(); \ + *(int *)p = v; \ + } while (0) +#else +#error "Unsupported architecture" +#endif + +/* + * Control block status and exception codes + */ +#define CBS_IDLE 0 +#define CBS_EXCEPTION 1 +#define CBS_ACTIVE 2 +#define CBS_CALL_OS 3 + +/* CB substatus bitmasks */ +#define CBSS_MSG_QUEUE_MASK 7 +#define CBSS_IMPLICIT_ABORT_ACTIVE_MASK 8 + +/* CB substatus message queue values (low 3 bits of substatus) */ +#define CBSS_NO_ERROR 0 +#define CBSS_LB_OVERFLOWED 1 +#define CBSS_QLIMIT_REACHED 2 +#define CBSS_PAGE_OVERFLOW 3 +#define CBSS_AMO_NACKED 4 +#define CBSS_PUT_NACKED 5 + +/* + * Structure used to fetch exception detail for CBs that terminate with + * CBS_EXCEPTION + */ +struct control_block_extended_exc_detail { + unsigned long cb; + int opc; + int ecause; + int exopc; + long exceptdet0; + int exceptdet1; +}; + +/* + * Instruction formats + */ + +/* + * Generic instruction format. + * This definition has precise bit field definitions. + */ +struct gru_instruction_bits { + /* DW 0 - low */ + unsigned int icmd: 1; + unsigned char ima: 3; /* CB_DelRep, unmapped mode */ + unsigned char reserved0: 4; + unsigned int xtype: 3; + unsigned int iaa0: 2; + unsigned int iaa1: 2; + unsigned char reserved1: 1; + unsigned char opc: 8; /* opcode */ + unsigned char exopc: 8; /* extended opcode */ + /* DW 0 - high */ + unsigned int idef2: 22; /* TRi0 */ + unsigned char reserved2: 2; + unsigned char istatus: 2; + unsigned char isubstatus:4; + unsigned char reserved3: 2; + /* DW 1 */ + unsigned long idef4; /* 42 bits: TRi1, BufSize */ + /* DW 2-6 */ + unsigned long idef1; /* BAddr0 */ + unsigned long idef5; /* Nelem */ + unsigned long idef6; /* Stride, Operand1 */ + unsigned long idef3; /* BAddr1, Value, Operand2 */ + unsigned long reserved4; + /* DW 7 */ + unsigned long avalue; /* AValue */ +}; + +/* + * Generic instruction with friendlier names. This format is used + * for inline instructions. + */ +struct gru_instruction { + /* DW 0 */ + unsigned int op32; /* icmd,xtype,iaa0,ima,opc */ + unsigned int tri0; + unsigned long tri1_bufsize; /* DW 1 */ + unsigned long baddr0; /* DW 2 */ + unsigned long nelem; /* DW 3 */ + unsigned long op1_stride; /* DW 4 */ + unsigned long op2_value_baddr1; /* DW 5 */ + unsigned long reserved0; /* DW 6 */ + unsigned long avalue; /* DW 7 */ +}; + +/* Some shifts and masks for the low 32 bits of a GRU command */ +#define GRU_CB_ICMD_SHFT 0 +#define GRU_CB_ICMD_MASK 0x1 +#define GRU_CB_XTYPE_SHFT 8 +#define GRU_CB_XTYPE_MASK 0x7 +#define GRU_CB_IAA0_SHFT 11 +#define GRU_CB_IAA0_MASK 0x3 +#define GRU_CB_IAA1_SHFT 13 +#define GRU_CB_IAA1_MASK 0x3 +#define GRU_CB_IMA_SHFT 1 +#define GRU_CB_IMA_MASK 0x3 +#define GRU_CB_OPC_SHFT 16 +#define GRU_CB_OPC_MASK 0xff +#define GRU_CB_EXOPC_SHFT 24 +#define GRU_CB_EXOPC_MASK 0xff + +/* GRU instruction opcodes (opc field) */ +#define OP_NOP 0x00 +#define OP_BCOPY 0x01 +#define OP_VLOAD 0x02 +#define OP_IVLOAD 0x03 +#define OP_VSTORE 0x04 +#define OP_IVSTORE 0x05 +#define OP_VSET 0x06 +#define OP_IVSET 0x07 +#define OP_MESQ 0x08 +#define OP_GAMXR 0x09 +#define OP_GAMIR 0x0a +#define OP_GAMIRR 0x0b +#define OP_GAMER 0x0c +#define OP_GAMERR 0x0d +#define OP_BSTORE 0x0e +#define OP_VFLUSH 0x0f + + +/* Extended opcodes values (exopc field) */ + +/* GAMIR - AMOs with implicit operands */ +#define EOP_IR_FETCH 0x01 /* Plain fetch of memory */ +#define EOP_IR_CLR 0x02 /* Fetch and clear */ +#define EOP_IR_INC 0x05 /* Fetch and increment */ +#define EOP_IR_DEC 0x07 /* Fetch and decrement */ +#define EOP_IR_QCHK1 0x0d /* Queue check, 64 byte msg */ +#define EOP_IR_QCHK2 0x0e /* Queue check, 128 byte msg */ + +/* GAMIRR - Registered AMOs with implicit operands */ +#define EOP_IRR_FETCH 0x01 /* Registered fetch of memory */ +#define EOP_IRR_CLR 0x02 /* Registered fetch and clear */ +#define EOP_IRR_INC 0x05 /* Registered fetch and increment */ +#define EOP_IRR_DEC 0x07 /* Registered fetch and decrement */ +#define EOP_IRR_DECZ 0x0f /* Registered fetch and decrement, update on zero*/ + +/* GAMER - AMOs with explicit operands */ +#define EOP_ER_SWAP 0x00 /* Exchange argument and memory */ +#define EOP_ER_OR 0x01 /* Logical OR with memory */ +#define EOP_ER_AND 0x02 /* Logical AND with memory */ +#define EOP_ER_XOR 0x03 /* Logical XOR with memory */ +#define EOP_ER_ADD 0x04 /* Add value to memory */ +#define EOP_ER_CSWAP 0x08 /* Compare with operand2, write operand1 if match*/ +#define EOP_ER_CADD 0x0c /* Queue check, operand1*64 byte msg */ + +/* GAMERR - Registered AMOs with explicit operands */ +#define EOP_ERR_SWAP 0x00 /* Exchange argument and memory */ +#define EOP_ERR_OR 0x01 /* Logical OR with memory */ +#define EOP_ERR_AND 0x02 /* Logical AND with memory */ +#define EOP_ERR_XOR 0x03 /* Logical XOR with memory */ +#define EOP_ERR_ADD 0x04 /* Add value to memory */ +#define EOP_ERR_CSWAP 0x08 /* Compare with operand2, write operand1 if match*/ +#define EOP_ERR_EPOLL 0x09 /* Poll for equality */ +#define EOP_ERR_NPOLL 0x0a /* Poll for inequality */ + +/* GAMXR - SGI Arithmetic unit */ +#define EOP_XR_CSWAP 0x0b /* Masked compare exchange */ + + +/* Transfer types (xtype field) */ +#define XTYPE_B 0x0 /* byte */ +#define XTYPE_S 0x1 /* short (2-byte) */ +#define XTYPE_W 0x2 /* word (4-byte) */ +#define XTYPE_DW 0x3 /* doubleword (8-byte) */ +#define XTYPE_CL 0x6 /* cacheline (64-byte) */ + + +/* Instruction access attributes (iaa0, iaa1 fields) */ +#define IAA_RAM 0x0 /* normal cached RAM access */ +#define IAA_NCRAM 0x2 /* noncoherent RAM access */ +#define IAA_MMIO 0x1 /* noncoherent memory-mapped I/O space */ +#define IAA_REGISTER 0x3 /* memory-mapped registers, etc. */ + + +/* Instruction mode attributes (ima field) */ +#define IMA_MAPPED 0x0 /* Virtual mode */ +#define IMA_CB_DELAY 0x1 /* hold read responses until status changes */ +#define IMA_UNMAPPED 0x2 /* bypass the TLBs (OS only) */ +#define IMA_INTERRUPT 0x4 /* Interrupt when instruction completes */ + +/* CBE ecause bits */ +#define CBE_CAUSE_RI (1 << 0) +#define CBE_CAUSE_INVALID_INSTRUCTION (1 << 1) +#define CBE_CAUSE_UNMAPPED_MODE_FORBIDDEN (1 << 2) +#define CBE_CAUSE_PE_CHECK_DATA_ERROR (1 << 3) +#define CBE_CAUSE_IAA_GAA_MISMATCH (1 << 4) +#define CBE_CAUSE_DATA_SEGMENT_LIMIT_EXCEPTION (1 << 5) +#define CBE_CAUSE_OS_FATAL_TLB_FAULT (1 << 6) +#define CBE_CAUSE_EXECUTION_HW_ERROR (1 << 7) +#define CBE_CAUSE_TLBHW_ERROR (1 << 8) +#define CBE_CAUSE_RA_REQUEST_TIMEOUT (1 << 9) +#define CBE_CAUSE_HA_REQUEST_TIMEOUT (1 << 10) +#define CBE_CAUSE_RA_RESPONSE_FATAL (1 << 11) +#define CBE_CAUSE_RA_RESPONSE_NON_FATAL (1 << 12) +#define CBE_CAUSE_HA_RESPONSE_FATAL (1 << 13) +#define CBE_CAUSE_HA_RESPONSE_NON_FATAL (1 << 14) +#define CBE_CAUSE_ADDRESS_SPACE_DECODE_ERROR (1 << 15) +#define CBE_CAUSE_RESPONSE_DATA_ERROR (1 << 16) +#define CBE_CAUSE_PROTOCOL_STATE_DATA_ERROR (1 << 17) + +/* + * Exceptions are retried for the following cases. If any OTHER bits are set + * in ecause, the exception is not retryable. + */ +#define EXCEPTION_RETRY_BITS (CBE_CAUSE_RESPONSE_DATA_ERROR | \ + CBE_CAUSE_RA_REQUEST_TIMEOUT | \ + CBE_CAUSE_TLBHW_ERROR | \ + CBE_CAUSE_HA_REQUEST_TIMEOUT) + +/* Message queue head structure */ +union gru_mesqhead { + unsigned long val; + struct { + unsigned int head; + unsigned int limit; + }; +}; + + +/* Generate the low word of a GRU instruction */ +static inline unsigned int +__opword(unsigned char opcode, unsigned char exopc, unsigned char xtype, + unsigned char iaa0, unsigned char iaa1, + unsigned char ima) +{ + return (1 << GRU_CB_ICMD_SHFT) | + (iaa0 << GRU_CB_IAA0_SHFT) | + (iaa1 << GRU_CB_IAA1_SHFT) | + (ima << GRU_CB_IMA_SHFT) | + (xtype << GRU_CB_XTYPE_SHFT) | + (opcode << GRU_CB_OPC_SHFT) | + (exopc << GRU_CB_EXOPC_SHFT); +} + +/* + * Prefetch a cacheline. Fetch is unconditional. Must page fault if + * no valid TLB entry is found. + * ??? should I use actual "load" or hardware prefetch??? + */ +static inline void gru_prefetch(void *p) +{ + *(volatile char *)p; +} + +/* + * Architecture specific intrinsics + */ +static inline void gru_flush_cache(void *p) +{ + __flush_cache(p); +} + +/* + * Store the lower 32 bits of the command including the "start" bit. Then + * start the instruction executing. + */ +static inline void gru_start_instruction(struct gru_instruction *ins, int op32) +{ + gru_ordered_store_int(ins, op32); +} + + +/* Convert "hints" to IMA */ +#define CB_IMA(h) ((h) | IMA_UNMAPPED) + +/* Convert data segment cache line index into TRI0 / TRI1 value */ +#define GRU_DINDEX(i) ((i) * GRU_CACHE_LINE_BYTES) + +/* Inline functions for GRU instructions. + * Note: + * - nelem and stride are in elements + * - tri0/tri1 is in bytes for the beginning of the data segment. + */ +static inline void gru_vload(void *cb, unsigned long mem_addr, + unsigned int tri0, unsigned char xtype, unsigned long nelem, + unsigned long stride, unsigned long hints) +{ + struct gru_instruction *ins = (struct gru_instruction *)cb; + + ins->baddr0 = (long)mem_addr; + ins->nelem = nelem; + ins->tri0 = tri0; + ins->op1_stride = stride; + gru_start_instruction(ins, __opword(OP_VLOAD, 0, xtype, IAA_RAM, 0, + CB_IMA(hints))); +} + +static inline void gru_vstore(void *cb, unsigned long mem_addr, + unsigned int tri0, unsigned char xtype, unsigned long nelem, + unsigned long stride, unsigned long hints) +{ + struct gru_instruction *ins = (void *)cb; + + ins->baddr0 = (long)mem_addr; + ins->nelem = nelem; + ins->tri0 = tri0; + ins->op1_stride = stride; + gru_start_instruction(ins, __opword(OP_VSTORE, 0, xtype, IAA_RAM, 0, + CB_IMA(hints))); +} + +static inline void gru_ivload(void *cb, unsigned long mem_addr, + unsigned int tri0, unsigned int tri1, unsigned char xtype, + unsigned long nelem, unsigned long hints) +{ + struct gru_instruction *ins = (void *)cb; + + ins->baddr0 = (long)mem_addr; + ins->nelem = nelem; + ins->tri0 = tri0; + ins->tri1_bufsize = tri1; + gru_start_instruction(ins, __opword(OP_IVLOAD, 0, xtype, IAA_RAM, 0, + CB_IMA(hints))); +} + +static inline void gru_ivstore(void *cb, unsigned long mem_addr, + unsigned int tri0, unsigned int tri1, + unsigned char xtype, unsigned long nelem, unsigned long hints) +{ + struct gru_instruction *ins = (void *)cb; + + ins->baddr0 = (long)mem_addr; + ins->nelem = nelem; + ins->tri0 = tri0; + ins->tri1_bufsize = tri1; + gru_start_instruction(ins, __opword(OP_IVSTORE, 0, xtype, IAA_RAM, 0, + CB_IMA(hints))); +} + +static inline void gru_vset(void *cb, unsigned long mem_addr, + unsigned long value, unsigned char xtype, unsigned long nelem, + unsigned long stride, unsigned long hints) +{ + struct gru_instruction *ins = (void *)cb; + + ins->baddr0 = (long)mem_addr; + ins->op2_value_baddr1 = value; + ins->nelem = nelem; + ins->op1_stride = stride; + gru_start_instruction(ins, __opword(OP_VSET, 0, xtype, IAA_RAM, 0, + CB_IMA(hints))); +} + +static inline void gru_ivset(void *cb, unsigned long mem_addr, + unsigned int tri1, unsigned long value, unsigned char xtype, + unsigned long nelem, unsigned long hints) +{ + struct gru_instruction *ins = (void *)cb; + + ins->baddr0 = (long)mem_addr; + ins->op2_value_baddr1 = value; + ins->nelem = nelem; + ins->tri1_bufsize = tri1; + gru_start_instruction(ins, __opword(OP_IVSET, 0, xtype, IAA_RAM, 0, + CB_IMA(hints))); +} + +static inline void gru_vflush(void *cb, unsigned long mem_addr, + unsigned long nelem, unsigned char xtype, unsigned long stride, + unsigned long hints) +{ + struct gru_instruction *ins = (void *)cb; + + ins->baddr0 = (long)mem_addr; + ins->op1_stride = stride; + ins->nelem = nelem; + gru_start_instruction(ins, __opword(OP_VFLUSH, 0, xtype, IAA_RAM, 0, + CB_IMA(hints))); +} + +static inline void gru_nop(void *cb, int hints) +{ + struct gru_instruction *ins = (void *)cb; + + gru_start_instruction(ins, __opword(OP_NOP, 0, 0, 0, 0, CB_IMA(hints))); +} + + +static inline void gru_bcopy(void *cb, const unsigned long src, + unsigned long dest, + unsigned int tri0, unsigned int xtype, unsigned long nelem, + unsigned int bufsize, unsigned long hints) +{ + struct gru_instruction *ins = (void *)cb; + + ins->baddr0 = (long)src; + ins->op2_value_baddr1 = (long)dest; + ins->nelem = nelem; + ins->tri0 = tri0; + ins->tri1_bufsize = bufsize; + gru_start_instruction(ins, __opword(OP_BCOPY, 0, xtype, IAA_RAM, + IAA_RAM, CB_IMA(hints))); +} + +static inline void gru_bstore(void *cb, const unsigned long src, + unsigned long dest, unsigned int tri0, unsigned int xtype, + unsigned long nelem, unsigned long hints) +{ + struct gru_instruction *ins = (void *)cb; + + ins->baddr0 = (long)src; + ins->op2_value_baddr1 = (long)dest; + ins->nelem = nelem; + ins->tri0 = tri0; + gru_start_instruction(ins, __opword(OP_BSTORE, 0, xtype, 0, IAA_RAM, + CB_IMA(hints))); +} + +static inline void gru_gamir(void *cb, int exopc, unsigned long src, + unsigned int xtype, unsigned long hints) +{ + struct gru_instruction *ins = (void *)cb; + + ins->baddr0 = (long)src; + gru_start_instruction(ins, __opword(OP_GAMIR, exopc, xtype, IAA_RAM, 0, + CB_IMA(hints))); +} + +static inline void gru_gamirr(void *cb, int exopc, unsigned long src, + unsigned int xtype, unsigned long hints) +{ + struct gru_instruction *ins = (void *)cb; + + ins->baddr0 = (long)src; + gru_start_instruction(ins, __opword(OP_GAMIRR, exopc, xtype, IAA_RAM, 0, + CB_IMA(hints))); +} + +static inline void gru_gamer(void *cb, int exopc, unsigned long src, + unsigned int xtype, + unsigned long operand1, unsigned long operand2, + unsigned long hints) +{ + struct gru_instruction *ins = (void *)cb; + + ins->baddr0 = (long)src; + ins->op1_stride = operand1; + ins->op2_value_baddr1 = operand2; + gru_start_instruction(ins, __opword(OP_GAMER, exopc, xtype, IAA_RAM, 0, + CB_IMA(hints))); +} + +static inline void gru_gamerr(void *cb, int exopc, unsigned long src, + unsigned int xtype, unsigned long operand1, + unsigned long operand2, unsigned long hints) +{ + struct gru_instruction *ins = (void *)cb; + + ins->baddr0 = (long)src; + ins->op1_stride = operand1; + ins->op2_value_baddr1 = operand2; + gru_start_instruction(ins, __opword(OP_GAMERR, exopc, xtype, IAA_RAM, 0, + CB_IMA(hints))); +} + +static inline void gru_gamxr(void *cb, unsigned long src, + unsigned int tri0, unsigned long hints) +{ + struct gru_instruction *ins = (void *)cb; + + ins->baddr0 = (long)src; + ins->nelem = 4; + gru_start_instruction(ins, __opword(OP_GAMXR, EOP_XR_CSWAP, XTYPE_DW, + IAA_RAM, 0, CB_IMA(hints))); +} + +static inline void gru_mesq(void *cb, unsigned long queue, + unsigned long tri0, unsigned long nelem, + unsigned long hints) +{ + struct gru_instruction *ins = (void *)cb; + + ins->baddr0 = (long)queue; + ins->nelem = nelem; + ins->tri0 = tri0; + gru_start_instruction(ins, __opword(OP_MESQ, 0, XTYPE_CL, IAA_RAM, 0, + CB_IMA(hints))); +} + +static inline unsigned long gru_get_amo_value(void *cb) +{ + struct gru_instruction *ins = (void *)cb; + + return ins->avalue; +} + +static inline int gru_get_amo_value_head(void *cb) +{ + struct gru_instruction *ins = (void *)cb; + + return ins->avalue & 0xffffffff; +} + +static inline int gru_get_amo_value_limit(void *cb) +{ + struct gru_instruction *ins = (void *)cb; + + return ins->avalue >> 32; +} + +static inline union gru_mesqhead gru_mesq_head(int head, int limit) +{ + union gru_mesqhead mqh; + + mqh.head = head; + mqh.limit = limit; + return mqh; +} + +/* + * Get struct control_block_extended_exc_detail for CB. + */ +extern int gru_get_cb_exception_detail(void *cb, + struct control_block_extended_exc_detail *excdet); + +#define GRU_EXC_STR_SIZE 256 + +extern int gru_check_status_proc(void *cb); +extern int gru_wait_proc(void *cb); +extern void gru_wait_abort_proc(void *cb); + +/* + * Control block definition for checking status + */ +struct gru_control_block_status { + unsigned int icmd :1; + unsigned int unused1 :31; + unsigned int unused2 :24; + unsigned int istatus :2; + unsigned int isubstatus :4; + unsigned int inused3 :2; +}; + +/* Get CB status */ +static inline int gru_get_cb_status(void *cb) +{ + struct gru_control_block_status *cbs = (void *)cb; + + return cbs->istatus; +} + +/* Get CB message queue substatus */ +static inline int gru_get_cb_message_queue_substatus(void *cb) +{ + struct gru_control_block_status *cbs = (void *)cb; + + return cbs->isubstatus & CBSS_MSG_QUEUE_MASK; +} + +/* Get CB substatus */ +static inline int gru_get_cb_substatus(void *cb) +{ + struct gru_control_block_status *cbs = (void *)cb; + + return cbs->isubstatus; +} + +/* Check the status of a CB. If the CB is in UPM mode, call the + * OS to handle the UPM status. + * Returns the CB status field value (0 for normal completion) + */ +static inline int gru_check_status(void *cb) +{ + struct gru_control_block_status *cbs = (void *)cb; + int ret = cbs->istatus; + + if (ret == CBS_CALL_OS) + ret = gru_check_status_proc(cb); + return ret; +} + +/* Wait for CB to complete. + * Returns the CB status field value (0 for normal completion) + */ +static inline int gru_wait(void *cb) +{ + struct gru_control_block_status *cbs = (void *)cb; + int ret = cbs->istatus;; + + if (ret != CBS_IDLE) + ret = gru_wait_proc(cb); + return ret; +} + +/* Wait for CB to complete. Aborts program if error. (Note: error does NOT + * mean TLB mis - only fatal errors such as memory parity error or user + * bugs will cause termination. + */ +static inline void gru_wait_abort(void *cb) +{ + struct gru_control_block_status *cbs = (void *)cb; + + if (cbs->istatus != CBS_IDLE) + gru_wait_abort_proc(cb); +} + + +/* + * Get a pointer to a control block + * gseg - GSeg address returned from gru_get_thread_gru_segment() + * index - index of desired CB + */ +static inline void *gru_get_cb_pointer(void *gseg, + int index) +{ + return gseg + GRU_CB_BASE + index * GRU_HANDLE_STRIDE; +} + +/* + * Get a pointer to a cacheline in the data segment portion of a GSeg + * gseg - GSeg address returned from gru_get_thread_gru_segment() + * index - index of desired cache line + */ +static inline void *gru_get_data_pointer(void *gseg, int index) +{ + return gseg + GRU_DS_BASE + index * GRU_CACHE_LINE_BYTES; +} + +/* + * Convert a vaddr into the tri index within the GSEG + * vaddr - virtual address of within gseg + */ +static inline int gru_get_tri(void *vaddr) +{ + return ((unsigned long)vaddr & (GRU_GSEG_PAGESIZE - 1)) - GRU_DS_BASE; +} +#endif /* __GRU_INSTRUCTIONS_H__ */ -- cgit v1.2.3 From 13d19498b0446cad2c394f9fbec8149b44a60c6e Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Tue, 29 Jul 2008 22:33:55 -0700 Subject: GRU Driver: driver internal header files This patch contains header files internal to the GRU driver. Signed-off-by: Jack Steiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-gru/gru.h | 67 +++++ drivers/misc/sgi-gru/grulib.h | 97 +++++++ drivers/misc/sgi-gru/grutables.h | 545 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 709 insertions(+) create mode 100644 drivers/misc/sgi-gru/gru.h create mode 100644 drivers/misc/sgi-gru/grulib.h create mode 100644 drivers/misc/sgi-gru/grutables.h (limited to 'drivers') diff --git a/drivers/misc/sgi-gru/gru.h b/drivers/misc/sgi-gru/gru.h new file mode 100644 index 00000000000..40df7cb3f0a --- /dev/null +++ b/drivers/misc/sgi-gru/gru.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __GRU_H__ +#define __GRU_H__ + +/* + * GRU architectural definitions + */ +#define GRU_CACHE_LINE_BYTES 64 +#define GRU_HANDLE_STRIDE 256 +#define GRU_CB_BASE 0 +#define GRU_DS_BASE 0x20000 + +/* + * Size used to map GRU GSeg + */ +#if defined CONFIG_IA64 +#define GRU_GSEG_PAGESIZE (256 * 1024UL) +#elif defined CONFIG_X86_64 +#define GRU_GSEG_PAGESIZE (256 * 1024UL) /* ZZZ 2MB ??? */ +#else +#error "Unsupported architecture" +#endif + +/* + * Structure for obtaining GRU resource information + */ +struct gru_chiplet_info { + int node; + int chiplet; + int blade; + int total_dsr_bytes; + int total_cbr; + int total_user_dsr_bytes; + int total_user_cbr; + int free_user_dsr_bytes; + int free_user_cbr; +}; + +/* Flags for GRU options on the gru_create_context() call */ +/* Select one of the follow 4 options to specify how TLB misses are handled */ +#define GRU_OPT_MISS_DEFAULT 0x0000 /* Use default mode */ +#define GRU_OPT_MISS_USER_POLL 0x0001 /* User will poll CB for faults */ +#define GRU_OPT_MISS_FMM_INTR 0x0002 /* Send interrupt to cpu to + handle fault */ +#define GRU_OPT_MISS_FMM_POLL 0x0003 /* Use system polling thread */ +#define GRU_OPT_MISS_MASK 0x0003 /* Mask for TLB MISS option */ + + + +#endif /* __GRU_H__ */ diff --git a/drivers/misc/sgi-gru/grulib.h b/drivers/misc/sgi-gru/grulib.h new file mode 100644 index 00000000000..e56e196a699 --- /dev/null +++ b/drivers/misc/sgi-gru/grulib.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __GRULIB_H__ +#define __GRULIB_H__ + +#define GRU_BASENAME "gru" +#define GRU_FULLNAME "/dev/gru" +#define GRU_IOCTL_NUM 'G' + +/* + * Maximum number of GRU segments that a user can have open + * ZZZ temp - set high for testing. Revisit. + */ +#define GRU_MAX_OPEN_CONTEXTS 32 + +/* Set Number of Request Blocks */ +#define GRU_CREATE_CONTEXT _IOWR(GRU_IOCTL_NUM, 1, void *) + +/* Register task as using the slice */ +#define GRU_SET_TASK_SLICE _IOWR(GRU_IOCTL_NUM, 5, void *) + +/* Fetch exception detail */ +#define GRU_USER_GET_EXCEPTION_DETAIL _IOWR(GRU_IOCTL_NUM, 6, void *) + +/* For user call_os handling - normally a TLB fault */ +#define GRU_USER_CALL_OS _IOWR(GRU_IOCTL_NUM, 8, void *) + +/* For user unload context */ +#define GRU_USER_UNLOAD_CONTEXT _IOWR(GRU_IOCTL_NUM, 9, void *) + +/* For fetching GRU chiplet status */ +#define GRU_GET_CHIPLET_STATUS _IOWR(GRU_IOCTL_NUM, 10, void *) + +/* For user TLB flushing (primarily for tests) */ +#define GRU_USER_FLUSH_TLB _IOWR(GRU_IOCTL_NUM, 50, void *) + +/* Get some config options (primarily for tests & emulator) */ +#define GRU_GET_CONFIG_INFO _IOWR(GRU_IOCTL_NUM, 51, void *) + +#define CONTEXT_WINDOW_BYTES(th) (GRU_GSEG_PAGESIZE * (th)) +#define THREAD_POINTER(p, th) (p + GRU_GSEG_PAGESIZE * (th)) + +/* + * Structure used to pass TLB flush parameters to the driver + */ +struct gru_create_context_req { + unsigned long gseg; + unsigned int data_segment_bytes; + unsigned int control_blocks; + unsigned int maximum_thread_count; + unsigned int options; +}; + +/* + * Structure used to pass unload context parameters to the driver + */ +struct gru_unload_context_req { + unsigned long gseg; +}; + +/* + * Structure used to pass TLB flush parameters to the driver + */ +struct gru_flush_tlb_req { + unsigned long gseg; + unsigned long vaddr; + size_t len; +}; + +/* + * GRU configuration info (temp - for testing) + */ +struct gru_config_info { + int cpus; + int blades; + int nodes; + int chiplets; + int fill[16]; +}; + +#endif /* __GRULIB_H__ */ diff --git a/drivers/misc/sgi-gru/grutables.h b/drivers/misc/sgi-gru/grutables.h new file mode 100644 index 00000000000..f97d8464012 --- /dev/null +++ b/drivers/misc/sgi-gru/grutables.h @@ -0,0 +1,545 @@ +/* + * SN Platform GRU Driver + * + * GRU DRIVER TABLES, MACROS, externs, etc + * + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __GRUTABLES_H__ +#define __GRUTABLES_H__ + +/* + * Tables: + * + * VDATA-VMA Data - Holds a few parameters. Head of linked list of + * GTS tables for threads using the GSEG + * GTS - Gru Thread State - contains info for managing a GSEG context. A + * GTS is allocated for each thread accessing a + * GSEG. + * GTD - GRU Thread Data - contains shadow copy of GRU data when GSEG is + * not loaded into a GRU + * GMS - GRU Memory Struct - Used to manage TLB shootdowns. Tracks GRUs + * where a GSEG has been loaded. Similar to + * an mm_struct but for GRU. + * + * GS - GRU State - Used to manage the state of a GRU chiplet + * BS - Blade State - Used to manage state of all GRU chiplets + * on a blade + * + * + * Normal task tables for task using GRU. + * - 2 threads in process + * - 2 GSEGs open in process + * - GSEG1 is being used by both threads + * - GSEG2 is used only by thread 2 + * + * task -->| + * task ---+---> mm ->------ (notifier) -------+-> gms + * | | + * |--> vma -> vdata ---> gts--->| GSEG1 (thread1) + * | | | + * | +-> gts--->| GSEG1 (thread2) + * | | + * |--> vma -> vdata ---> gts--->| GSEG2 (thread2) + * . + * . + * + * GSEGs are marked DONTCOPY on fork + * + * At open + * file.private_data -> NULL + * + * At mmap, + * vma -> vdata + * + * After gseg reference + * vma -> vdata ->gts + * + * After fork + * parent + * vma -> vdata -> gts + * child + * (vma is not copied) + * + */ + +#include +#include +#include +#include +#include +#include "gru.h" +#include "gruhandles.h" + +extern struct gru_stats_s gru_stats; +extern struct gru_blade_state *gru_base[]; +extern unsigned long gru_start_paddr, gru_end_paddr; + +#define GRU_MAX_BLADES MAX_NUMNODES +#define GRU_MAX_GRUS (GRU_MAX_BLADES * GRU_CHIPLETS_PER_BLADE) + +#define GRU_DRIVER_ID_STR "SGI GRU Device Driver" +#define GRU_DRIVER_VERSION_STR "0.80" + +/* + * GRU statistics. + */ +struct gru_stats_s { + atomic_long_t vdata_alloc; + atomic_long_t vdata_free; + atomic_long_t gts_alloc; + atomic_long_t gts_free; + atomic_long_t vdata_double_alloc; + atomic_long_t gts_double_allocate; + atomic_long_t assign_context; + atomic_long_t assign_context_failed; + atomic_long_t free_context; + atomic_long_t load_context; + atomic_long_t unload_context; + atomic_long_t steal_context; + atomic_long_t steal_context_failed; + atomic_long_t nopfn; + atomic_long_t break_cow; + atomic_long_t asid_new; + atomic_long_t asid_next; + atomic_long_t asid_wrap; + atomic_long_t asid_reuse; + atomic_long_t intr; + atomic_long_t call_os; + atomic_long_t call_os_check_for_bug; + atomic_long_t call_os_wait_queue; + atomic_long_t user_flush_tlb; + atomic_long_t user_unload_context; + atomic_long_t user_exception; + atomic_long_t set_task_slice; + atomic_long_t migrate_check; + atomic_long_t migrated_retarget; + atomic_long_t migrated_unload; + atomic_long_t migrated_unload_delay; + atomic_long_t migrated_nopfn_retarget; + atomic_long_t migrated_nopfn_unload; + atomic_long_t tlb_dropin; + atomic_long_t tlb_dropin_fail_no_asid; + atomic_long_t tlb_dropin_fail_upm; + atomic_long_t tlb_dropin_fail_invalid; + atomic_long_t tlb_dropin_fail_range_active; + atomic_long_t tlb_dropin_fail_idle; + atomic_long_t tlb_dropin_fail_fmm; + atomic_long_t mmu_invalidate_range; + atomic_long_t mmu_invalidate_page; + atomic_long_t mmu_clear_flush_young; + atomic_long_t flush_tlb; + atomic_long_t flush_tlb_gru; + atomic_long_t flush_tlb_gru_tgh; + atomic_long_t flush_tlb_gru_zero_asid; + + atomic_long_t copy_gpa; + + atomic_long_t mesq_receive; + atomic_long_t mesq_receive_none; + atomic_long_t mesq_send; + atomic_long_t mesq_send_failed; + atomic_long_t mesq_noop; + atomic_long_t mesq_send_unexpected_error; + atomic_long_t mesq_send_lb_overflow; + atomic_long_t mesq_send_qlimit_reached; + atomic_long_t mesq_send_amo_nacked; + atomic_long_t mesq_send_put_nacked; + atomic_long_t mesq_qf_not_full; + atomic_long_t mesq_qf_locked; + atomic_long_t mesq_qf_noop_not_full; + atomic_long_t mesq_qf_switch_head_failed; + atomic_long_t mesq_qf_unexpected_error; + atomic_long_t mesq_noop_unexpected_error; + atomic_long_t mesq_noop_lb_overflow; + atomic_long_t mesq_noop_qlimit_reached; + atomic_long_t mesq_noop_amo_nacked; + atomic_long_t mesq_noop_put_nacked; + +}; + +#define OPT_DPRINT 1 +#define OPT_STATS 2 +#define GRU_QUICKLOOK 4 + + +#define IRQ_GRU 110 /* Starting IRQ number for interrupts */ + +/* Delay in jiffies between attempts to assign a GRU context */ +#define GRU_ASSIGN_DELAY ((HZ * 20) / 1000) + +/* + * If a process has it's context stolen, min delay in jiffies before trying to + * steal a context from another process. + */ +#define GRU_STEAL_DELAY ((HZ * 200) / 1000) + +#define STAT(id) do { \ + if (options & OPT_STATS) \ + atomic_long_inc(&gru_stats.id); \ + } while (0) + +#ifdef CONFIG_SGI_GRU_DEBUG +#define gru_dbg(dev, fmt, x...) \ + do { \ + if (options & OPT_DPRINT) \ + dev_dbg(dev, "%s: " fmt, __func__, x); \ + } while (0) +#else +#define gru_dbg(x...) +#endif + +/*----------------------------------------------------------------------------- + * ASID management + */ +#define MAX_ASID 0xfffff0 +#define MIN_ASID 8 +#define ASID_INC 8 /* number of regions */ + +/* Generate a GRU asid value from a GRU base asid & a virtual address. */ +#if defined CONFIG_IA64 +#define VADDR_HI_BIT 64 +#define GRUREGION(addr) ((addr) >> (VADDR_HI_BIT - 3) & 3) +#elif defined __x86_64 +#define VADDR_HI_BIT 48 +#define GRUREGION(addr) (0) /* ZZZ could do better */ +#else +#error "Unsupported architecture" +#endif +#define GRUASID(asid, addr) ((asid) + GRUREGION(addr)) + +/*------------------------------------------------------------------------------ + * File & VMS Tables + */ + +struct gru_state; + +/* + * This structure is pointed to from the mmstruct via the notifier pointer. + * There is one of these per address space. + */ +struct gru_mm_tracker { + unsigned int mt_asid_gen; /* ASID wrap count */ + int mt_asid; /* current base ASID for gru */ + unsigned short mt_ctxbitmap; /* bitmap of contexts using + asid */ +}; + +struct gru_mm_struct { + struct mmu_notifier ms_notifier; + atomic_t ms_refcnt; + spinlock_t ms_asid_lock; /* protects ASID assignment */ + atomic_t ms_range_active;/* num range_invals active */ + char ms_released; + wait_queue_head_t ms_wait_queue; + DECLARE_BITMAP(ms_asidmap, GRU_MAX_GRUS); + struct gru_mm_tracker ms_asids[GRU_MAX_GRUS]; +}; + +/* + * One of these structures is allocated when a GSEG is mmaped. The + * structure is pointed to by the vma->vm_private_data field in the vma struct. + */ +struct gru_vma_data { + spinlock_t vd_lock; /* Serialize access to vma */ + struct list_head vd_head; /* head of linked list of gts */ + long vd_user_options;/* misc user option flags */ + int vd_cbr_au_count; + int vd_dsr_au_count; +}; + +/* + * One of these is allocated for each thread accessing a mmaped GRU. A linked + * list of these structure is hung off the struct gru_vma_data in the mm_struct. + */ +struct gru_thread_state { + struct list_head ts_next; /* list - head at vma-private */ + struct mutex ts_ctxlock; /* load/unload CTX lock */ + struct mm_struct *ts_mm; /* mm currently mapped to + context */ + struct vm_area_struct *ts_vma; /* vma of GRU context */ + struct gru_state *ts_gru; /* GRU where the context is + loaded */ + struct gru_mm_struct *ts_gms; /* asid & ioproc struct */ + unsigned long ts_cbr_map; /* map of allocated CBRs */ + unsigned long ts_dsr_map; /* map of allocated DATA + resources */ + unsigned long ts_steal_jiffies;/* jiffies when context last + stolen */ + long ts_user_options;/* misc user option flags */ + pid_t ts_tgid_owner; /* task that is using the + context - for migration */ + int ts_tsid; /* thread that owns the + structure */ + int ts_tlb_int_select;/* target cpu if interrupts + enabled */ + int ts_ctxnum; /* context number where the + context is loaded */ + atomic_t ts_refcnt; /* reference count GTS */ + unsigned char ts_dsr_au_count;/* Number of DSR resources + required for contest */ + unsigned char ts_cbr_au_count;/* Number of CBR resources + required for contest */ + char ts_force_unload;/* force context to be unloaded + after migration */ + char ts_cbr_idx[GRU_CBR_AU];/* CBR numbers of each + allocated CB */ + unsigned long ts_gdata[0]; /* save area for GRU data (CB, + DS, CBE) */ +}; + +/* + * Threaded programs actually allocate an array of GSEGs when a context is + * created. Each thread uses a separate GSEG. TSID is the index into the GSEG + * array. + */ +#define TSID(a, v) (((a) - (v)->vm_start) / GRU_GSEG_PAGESIZE) +#define UGRUADDR(gts) ((gts)->ts_vma->vm_start + \ + (gts)->ts_tsid * GRU_GSEG_PAGESIZE) + +#define NULLCTX (-1) /* if context not loaded into GRU */ + +/*----------------------------------------------------------------------------- + * GRU State Tables + */ + +/* + * One of these exists for each GRU chiplet. + */ +struct gru_state { + struct gru_blade_state *gs_blade; /* GRU state for entire + blade */ + unsigned long gs_gru_base_paddr; /* Physical address of + gru segments (64) */ + void *gs_gru_base_vaddr; /* Virtual address of + gru segments (64) */ + unsigned char gs_gid; /* unique GRU number */ + unsigned char gs_tgh_local_shift; /* used to pick TGH for + local flush */ + unsigned char gs_tgh_first_remote; /* starting TGH# for + remote flush */ + unsigned short gs_blade_id; /* blade of GRU */ + spinlock_t gs_asid_lock; /* lock used for + assigning asids */ + spinlock_t gs_lock; /* lock used for + assigning contexts */ + + /* -- the following are protected by the gs_asid_lock spinlock ---- */ + unsigned int gs_asid; /* Next availe ASID */ + unsigned int gs_asid_limit; /* Limit of available + ASIDs */ + unsigned int gs_asid_gen; /* asid generation. + Inc on wrap */ + + /* --- the following fields are protected by the gs_lock spinlock --- */ + unsigned long gs_context_map; /* bitmap to manage + contexts in use */ + unsigned long gs_cbr_map; /* bitmap to manage CB + resources */ + unsigned long gs_dsr_map; /* bitmap used to manage + DATA resources */ + unsigned int gs_reserved_cbrs; /* Number of kernel- + reserved cbrs */ + unsigned int gs_reserved_dsr_bytes; /* Bytes of kernel- + reserved dsrs */ + unsigned short gs_active_contexts; /* number of contexts + in use */ + struct gru_thread_state *gs_gts[GRU_NUM_CCH]; /* GTS currently using + the context */ +}; + +/* + * This structure contains the GRU state for all the GRUs on a blade. + */ +struct gru_blade_state { + void *kernel_cb; /* First kernel + reserved cb */ + void *kernel_dsr; /* First kernel + reserved DSR */ + /* ---- the following are protected by the bs_lock spinlock ---- */ + spinlock_t bs_lock; /* lock used for + stealing contexts */ + int bs_lru_ctxnum; /* STEAL - last context + stolen */ + struct gru_state *bs_lru_gru; /* STEAL - last gru + stolen */ + + struct gru_state bs_grus[GRU_CHIPLETS_PER_BLADE]; +}; + +/*----------------------------------------------------------------------------- + * Address Primitives + */ +#define get_tfm_for_cpu(g, c) \ + ((struct gru_tlb_fault_map *)get_tfm((g)->gs_gru_base_vaddr, (c))) +#define get_tfh_by_index(g, i) \ + ((struct gru_tlb_fault_handle *)get_tfh((g)->gs_gru_base_vaddr, (i))) +#define get_tgh_by_index(g, i) \ + ((struct gru_tlb_global_handle *)get_tgh((g)->gs_gru_base_vaddr, (i))) +#define get_cbe_by_index(g, i) \ + ((struct gru_control_block_extended *)get_cbe((g)->gs_gru_base_vaddr,\ + (i))) + +/*----------------------------------------------------------------------------- + * Useful Macros + */ + +/* Given a blade# & chiplet#, get a pointer to the GRU */ +#define get_gru(b, c) (&gru_base[b]->bs_grus[c]) + +/* Number of bytes to save/restore when unloading/loading GRU contexts */ +#define DSR_BYTES(dsr) ((dsr) * GRU_DSR_AU_BYTES) +#define CBR_BYTES(cbr) ((cbr) * GRU_HANDLE_BYTES * GRU_CBR_AU_SIZE * 2) + +/* Convert a user CB number to the actual CBRNUM */ +#define thread_cbr_number(gts, n) ((gts)->ts_cbr_idx[(n) / GRU_CBR_AU_SIZE] \ + * GRU_CBR_AU_SIZE + (n) % GRU_CBR_AU_SIZE) + +/* Convert a gid to a pointer to the GRU */ +#define GID_TO_GRU(gid) \ + (gru_base[(gid) / GRU_CHIPLETS_PER_BLADE] ? \ + (&gru_base[(gid) / GRU_CHIPLETS_PER_BLADE]-> \ + bs_grus[(gid) % GRU_CHIPLETS_PER_BLADE]) : \ + NULL) + +/* Scan all active GRUs in a GRU bitmap */ +#define for_each_gru_in_bitmap(gid, map) \ + for ((gid) = find_first_bit((map), GRU_MAX_GRUS); (gid) < GRU_MAX_GRUS;\ + (gid)++, (gid) = find_next_bit((map), GRU_MAX_GRUS, (gid))) + +/* Scan all active GRUs on a specific blade */ +#define for_each_gru_on_blade(gru, nid, i) \ + for ((gru) = gru_base[nid]->bs_grus, (i) = 0; \ + (i) < GRU_CHIPLETS_PER_BLADE; \ + (i)++, (gru)++) + +/* Scan all active GTSs on a gru. Note: must hold ss_lock to use this macro. */ +#define for_each_gts_on_gru(gts, gru, ctxnum) \ + for ((ctxnum) = 0; (ctxnum) < GRU_NUM_CCH; (ctxnum)++) \ + if (((gts) = (gru)->gs_gts[ctxnum])) + +/* Scan each CBR whose bit is set in a TFM (or copy of) */ +#define for_each_cbr_in_tfm(i, map) \ + for ((i) = find_first_bit(map, GRU_NUM_CBE); \ + (i) < GRU_NUM_CBE; \ + (i)++, (i) = find_next_bit(map, GRU_NUM_CBE, i)) + +/* Scan each CBR in a CBR bitmap. Note: multiple CBRs in an allocation unit */ +#define for_each_cbr_in_allocation_map(i, map, k) \ + for ((k) = find_first_bit(map, GRU_CBR_AU); (k) < GRU_CBR_AU; \ + (k) = find_next_bit(map, GRU_CBR_AU, (k) + 1)) \ + for ((i) = (k)*GRU_CBR_AU_SIZE; \ + (i) < ((k) + 1) * GRU_CBR_AU_SIZE; (i)++) + +/* Scan each DSR in a DSR bitmap. Note: multiple DSRs in an allocation unit */ +#define for_each_dsr_in_allocation_map(i, map, k) \ + for ((k) = find_first_bit((const unsigned long *)map, GRU_DSR_AU);\ + (k) < GRU_DSR_AU; \ + (k) = find_next_bit((const unsigned long *)map, \ + GRU_DSR_AU, (k) + 1)) \ + for ((i) = (k) * GRU_DSR_AU_CL; \ + (i) < ((k) + 1) * GRU_DSR_AU_CL; (i)++) + +#define gseg_physical_address(gru, ctxnum) \ + ((gru)->gs_gru_base_paddr + ctxnum * GRU_GSEG_STRIDE) +#define gseg_virtual_address(gru, ctxnum) \ + ((gru)->gs_gru_base_vaddr + ctxnum * GRU_GSEG_STRIDE) + +/*----------------------------------------------------------------------------- + * Lock / Unlock GRU handles + * Use the "delresp" bit in the handle as a "lock" bit. + */ + +/* Lock hierarchy checking enabled only in emulator */ + +static inline void __lock_handle(void *h) +{ + while (test_and_set_bit(1, h)) + cpu_relax(); +} + +static inline void __unlock_handle(void *h) +{ + clear_bit(1, h); +} + +static inline void lock_cch_handle(struct gru_context_configuration_handle *cch) +{ + __lock_handle(cch); +} + +static inline void unlock_cch_handle(struct gru_context_configuration_handle + *cch) +{ + __unlock_handle(cch); +} + +static inline void lock_tgh_handle(struct gru_tlb_global_handle *tgh) +{ + __lock_handle(tgh); +} + +static inline void unlock_tgh_handle(struct gru_tlb_global_handle *tgh) +{ + __unlock_handle(tgh); +} + +/*----------------------------------------------------------------------------- + * Function prototypes & externs + */ +struct gru_unload_context_req; + +extern struct vm_operations_struct gru_vm_ops; +extern struct device *grudev; + +extern struct gru_vma_data *gru_alloc_vma_data(struct vm_area_struct *vma, + int tsid); +extern struct gru_thread_state *gru_find_thread_state(struct vm_area_struct + *vma, int tsid); +extern struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct + *vma, int tsid); +extern void gru_unload_context(struct gru_thread_state *gts, int savestate); +extern void gts_drop(struct gru_thread_state *gts); +extern void gru_tgh_flush_init(struct gru_state *gru); +extern int gru_kservices_init(struct gru_state *gru); +extern irqreturn_t gru_intr(int irq, void *dev_id); +extern int gru_handle_user_call_os(unsigned long address); +extern int gru_user_flush_tlb(unsigned long arg); +extern int gru_user_unload_context(unsigned long arg); +extern int gru_get_exception_detail(unsigned long arg); +extern int gru_set_task_slice(long address); +extern int gru_cpu_fault_map_id(void); +extern struct vm_area_struct *gru_find_vma(unsigned long vaddr); +extern void gru_flush_all_tlb(struct gru_state *gru); +extern int gru_proc_init(void); +extern void gru_proc_exit(void); + +extern unsigned long reserve_gru_cb_resources(struct gru_state *gru, + int cbr_au_count, char *cbmap); +extern unsigned long reserve_gru_ds_resources(struct gru_state *gru, + int dsr_au_count, char *dsmap); +extern int gru_fault(struct vm_area_struct *, struct vm_fault *vmf); +extern struct gru_mm_struct *gru_register_mmu_notifier(void); +extern void gru_drop_mmu_notifier(struct gru_mm_struct *gms); + +extern void gru_flush_tlb_range(struct gru_mm_struct *gms, unsigned long start, + unsigned long len); + +extern unsigned long options; + +#endif /* __GRUTABLES_H__ */ -- cgit v1.2.3 From b2fb06fcb6d6c9912b43e61394891e3994d4b613 Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Tue, 29 Jul 2008 22:33:56 -0700 Subject: GRU Driver: kernel services header files This patch contains the header file used to export GRU services to other kernel drivers such as XPMEM or XPNET. Signed-off-by: Jack Steiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-gru/grukservices.h | 134 ++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 drivers/misc/sgi-gru/grukservices.h (limited to 'drivers') diff --git a/drivers/misc/sgi-gru/grukservices.h b/drivers/misc/sgi-gru/grukservices.h new file mode 100644 index 00000000000..eb17e0a3ac6 --- /dev/null +++ b/drivers/misc/sgi-gru/grukservices.h @@ -0,0 +1,134 @@ + +/* + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __GRU_KSERVICES_H_ +#define __GRU_KSERVICES_H_ + + +/* + * Message queues using the GRU to send/receive messages. + * + * These function allow the user to create a message queue for + * sending/receiving 1 or 2 cacheline messages using the GRU. + * + * Processes SENDING messages will use a kernel CBR/DSR to send + * the message. This is transparent to the caller. + * + * The receiver does not use any GRU resources. + * + * The functions support: + * - single receiver + * - multiple senders + * - cross partition message + * + * Missing features ZZZ: + * - user options for dealing with timeouts, queue full, etc. + * - gru_create_message_queue() needs interrupt vector info + */ + +/* + * Initialize a user allocated chunk of memory to be used as + * a message queue. The caller must ensure that the queue is + * in contiguous physical memory and is cacheline aligned. + * + * Message queue size is the total number of bytes allocated + * to the queue including a 2 cacheline header that is used + * to manage the queue. + * + * Input: + * p pointer to user allocated memory. + * bytes size of message queue in bytes + * + * Errors: + * 0 OK + * >0 error + */ +extern int gru_create_message_queue(void *p, unsigned int bytes); + +/* + * Send a message to a message queue. + * + * Note: The message queue transport mechanism uses the first 32 + * bits of the message. Users should avoid using these bits. + * + * + * Input: + * xmq message queue - must be a UV global physical address + * mesg pointer to message. Must be 64-bit aligned + * bytes size of message in bytes + * + * Output: + * 0 message sent + * >0 Send failure - see error codes below + * + */ +extern int gru_send_message_gpa(unsigned long mq_gpa, void *mesg, + unsigned int bytes); + +/* Status values for gru_send_message() */ +#define MQE_OK 0 /* message sent successfully */ +#define MQE_CONGESTION 1 /* temporary congestion, try again */ +#define MQE_QUEUE_FULL 2 /* queue is full */ +#define MQE_UNEXPECTED_CB_ERR 3 /* unexpected CB error */ +#define MQE_PAGE_OVERFLOW 10 /* BUG - queue overflowed a page */ +#define MQE_BUG_NO_RESOURCES 11 /* BUG - could not alloc GRU cb/dsr */ + +/* + * Advance the receive pointer for the message queue to the next message. + * Note: current API requires messages to be gotten & freed in order. Future + * API extensions may allow for out-of-order freeing. + * + * Input + * mq message queue + * mesq message being freed + */ +extern void gru_free_message(void *mq, void *mesq); + +/* + * Get next message from message queue. Returns pointer to + * message OR NULL if no message present. + * User must call gru_free_message() after message is processed + * in order to move the queue pointers to next message. + * + * Input + * mq message queue + * + * Output: + * p pointer to message + * NULL no message available + */ +extern void *gru_get_next_message(void *mq); + + +/* + * Copy data using the GRU. Source or destination can be located in a remote + * partition. + * + * Input: + * dest_gpa destination global physical address + * src_gpa source global physical address + * bytes number of bytes to copy + * + * Output: + * 0 OK + * >0 error + */ +extern int gru_copy_gpa(unsigned long dest_gpa, unsigned long src_gpa, + unsigned int bytes); + +#endif /* __GRU_KSERVICES_H_ */ -- cgit v1.2.3 From 78cf1de49b11c0e2edb35cce91ac6c279cc852b3 Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Tue, 29 Jul 2008 22:33:56 -0700 Subject: GRU Driver: driver initialization, file & vma ops This file contains the functions for initializing the driver, handling file & vma operations and for processing IOCTL requests from the user. Signed-off-by: Jack Steiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-gru/grufile.c | 481 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 481 insertions(+) create mode 100644 drivers/misc/sgi-gru/grufile.c (limited to 'drivers') diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c new file mode 100644 index 00000000000..09c9c65ff9d --- /dev/null +++ b/drivers/misc/sgi-gru/grufile.c @@ -0,0 +1,481 @@ +/* + * SN Platform GRU Driver + * + * FILE OPERATIONS & DRIVER INITIALIZATION + * + * This file supports the user system call for file open, close, mmap, etc. + * This also incudes the driver initialization code. + * + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gru.h" +#include "grulib.h" +#include "grutables.h" + +#if defined CONFIG_X86_64 +#include +#include +#define IS_UV() is_uv_system() +#elif defined CONFIG_IA64 +#include +#include +/* temp support for running on hardware simulator */ +#define IS_UV() IS_MEDUSA() || ia64_platform_is("uv") +#else +#define IS_UV() 0 +#endif + +#include +#include + +struct gru_blade_state *gru_base[GRU_MAX_BLADES] __read_mostly; +unsigned long gru_start_paddr, gru_end_paddr __read_mostly; +struct gru_stats_s gru_stats; + +/* Guaranteed user available resources on each node */ +static int max_user_cbrs, max_user_dsr_bytes; + +static struct file_operations gru_fops; +static struct miscdevice gru_miscdev; + + +/* + * gru_vma_close + * + * Called when unmapping a device mapping. Frees all gru resources + * and tables belonging to the vma. + */ +static void gru_vma_close(struct vm_area_struct *vma) +{ + struct gru_vma_data *vdata; + struct gru_thread_state *gts; + struct list_head *entry, *next; + + if (!vma->vm_private_data) + return; + + vdata = vma->vm_private_data; + vma->vm_private_data = NULL; + gru_dbg(grudev, "vma %p, file %p, vdata %p\n", vma, vma->vm_file, + vdata); + list_for_each_safe(entry, next, &vdata->vd_head) { + gts = + list_entry(entry, struct gru_thread_state, ts_next); + list_del(>s->ts_next); + mutex_lock(>s->ts_ctxlock); + if (gts->ts_gru) + gru_unload_context(gts, 0); + mutex_unlock(>s->ts_ctxlock); + gts_drop(gts); + } + kfree(vdata); + STAT(vdata_free); +} + +/* + * gru_file_mmap + * + * Called when mmaping the device. Initializes the vma with a fault handler + * and private data structure necessary to allocate, track, and free the + * underlying pages. + */ +static int gru_file_mmap(struct file *file, struct vm_area_struct *vma) +{ + if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) != (VM_SHARED | VM_WRITE)) + return -EPERM; + + vma->vm_flags |= + (VM_IO | VM_DONTCOPY | VM_LOCKED | VM_DONTEXPAND | VM_PFNMAP | + VM_RESERVED); + vma->vm_page_prot = PAGE_SHARED; + vma->vm_ops = &gru_vm_ops; + + vma->vm_private_data = gru_alloc_vma_data(vma, 0); + if (!vma->vm_private_data) + return -ENOMEM; + + gru_dbg(grudev, "file %p, vaddr 0x%lx, vma %p, vdata %p\n", + file, vma->vm_start, vma, vma->vm_private_data); + return 0; +} + +/* + * Create a new GRU context + */ +static int gru_create_new_context(unsigned long arg) +{ + struct gru_create_context_req req; + struct vm_area_struct *vma; + struct gru_vma_data *vdata; + int ret = -EINVAL; + + + if (copy_from_user(&req, (void __user *)arg, sizeof(req))) + return -EFAULT; + + if (req.data_segment_bytes == 0 || + req.data_segment_bytes > max_user_dsr_bytes) + return -EINVAL; + if (!req.control_blocks || !req.maximum_thread_count || + req.control_blocks > max_user_cbrs) + return -EINVAL; + + if (!(req.options & GRU_OPT_MISS_MASK)) + req.options |= GRU_OPT_MISS_FMM_INTR; + + down_write(¤t->mm->mmap_sem); + vma = gru_find_vma(req.gseg); + if (vma) { + vdata = vma->vm_private_data; + vdata->vd_user_options = req.options; + vdata->vd_dsr_au_count = + GRU_DS_BYTES_TO_AU(req.data_segment_bytes); + vdata->vd_cbr_au_count = GRU_CB_COUNT_TO_AU(req.control_blocks); + ret = 0; + } + up_write(¤t->mm->mmap_sem); + + return ret; +} + +/* + * Get GRU configuration info (temp - for emulator testing) + */ +static long gru_get_config_info(unsigned long arg) +{ + struct gru_config_info info; + int nodesperblade; + + if (num_online_nodes() > 1 && + (uv_node_to_blade_id(1) == uv_node_to_blade_id(0))) + nodesperblade = 2; + else + nodesperblade = 1; + info.cpus = num_online_cpus(); + info.nodes = num_online_nodes(); + info.blades = info.nodes / nodesperblade; + info.chiplets = GRU_CHIPLETS_PER_BLADE * info.blades; + + if (copy_to_user((void __user *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; +} + +/* + * Get GRU chiplet status + */ +static long gru_get_chiplet_status(unsigned long arg) +{ + struct gru_state *gru; + struct gru_chiplet_info info; + + if (copy_from_user(&info, (void __user *)arg, sizeof(info))) + return -EFAULT; + + if (info.node == -1) + info.node = numa_node_id(); + if (info.node >= num_possible_nodes() || + info.chiplet >= GRU_CHIPLETS_PER_HUB || + info.node < 0 || info.chiplet < 0) + return -EINVAL; + + info.blade = uv_node_to_blade_id(info.node); + gru = get_gru(info.blade, info.chiplet); + + info.total_dsr_bytes = GRU_NUM_DSR_BYTES; + info.total_cbr = GRU_NUM_CB; + info.total_user_dsr_bytes = GRU_NUM_DSR_BYTES - + gru->gs_reserved_dsr_bytes; + info.total_user_cbr = GRU_NUM_CB - gru->gs_reserved_cbrs; + info.free_user_dsr_bytes = hweight64(gru->gs_dsr_map) * + GRU_DSR_AU_BYTES; + info.free_user_cbr = hweight64(gru->gs_cbr_map) * GRU_CBR_AU_SIZE; + + if (copy_to_user((void __user *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; +} + +/* + * gru_file_unlocked_ioctl + * + * Called to update file attributes via IOCTL calls. + */ +static long gru_file_unlocked_ioctl(struct file *file, unsigned int req, + unsigned long arg) +{ + int err = -EBADRQC; + + gru_dbg(grudev, "file %p\n", file); + + switch (req) { + case GRU_CREATE_CONTEXT: + err = gru_create_new_context(arg); + break; + case GRU_SET_TASK_SLICE: + err = gru_set_task_slice(arg); + break; + case GRU_USER_GET_EXCEPTION_DETAIL: + err = gru_get_exception_detail(arg); + break; + case GRU_USER_UNLOAD_CONTEXT: + err = gru_user_unload_context(arg); + break; + case GRU_GET_CHIPLET_STATUS: + err = gru_get_chiplet_status(arg); + break; + case GRU_USER_FLUSH_TLB: + err = gru_user_flush_tlb(arg); + break; + case GRU_USER_CALL_OS: + err = gru_handle_user_call_os(arg); + break; + case GRU_GET_CONFIG_INFO: + err = gru_get_config_info(arg); + break; + } + return err; +} + +/* + * Called at init time to build tables for all GRUs that are present in the + * system. + */ +static void gru_init_chiplet(struct gru_state *gru, unsigned long paddr, + void *vaddr, int nid, int bid, int grunum) +{ + spin_lock_init(&gru->gs_lock); + spin_lock_init(&gru->gs_asid_lock); + gru->gs_gru_base_paddr = paddr; + gru->gs_gru_base_vaddr = vaddr; + gru->gs_gid = bid * GRU_CHIPLETS_PER_BLADE + grunum; + gru->gs_blade = gru_base[bid]; + gru->gs_blade_id = bid; + gru->gs_cbr_map = (GRU_CBR_AU == 64) ? ~0 : (1UL << GRU_CBR_AU) - 1; + gru->gs_dsr_map = (1UL << GRU_DSR_AU) - 1; + gru_tgh_flush_init(gru); + gru_dbg(grudev, "bid %d, nid %d, gru %x, vaddr %p (0x%lx)\n", + bid, nid, gru->gs_gid, gru->gs_gru_base_vaddr, + gru->gs_gru_base_paddr); + gru_kservices_init(gru); +} + +static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr) +{ + int pnode, nid, bid, chip; + int cbrs, dsrbytes, n; + int order = get_order(sizeof(struct gru_blade_state)); + struct page *page; + struct gru_state *gru; + unsigned long paddr; + void *vaddr; + + max_user_cbrs = GRU_NUM_CB; + max_user_dsr_bytes = GRU_NUM_DSR_BYTES; + for_each_online_node(nid) { + bid = uv_node_to_blade_id(nid); + pnode = uv_node_to_pnode(nid); + if (gru_base[bid]) + continue; + page = alloc_pages_node(nid, GFP_KERNEL, order); + if (!page) + goto fail; + gru_base[bid] = page_address(page); + memset(gru_base[bid], 0, sizeof(struct gru_blade_state)); + gru_base[bid]->bs_lru_gru = &gru_base[bid]->bs_grus[0]; + spin_lock_init(&gru_base[bid]->bs_lock); + + dsrbytes = 0; + cbrs = 0; + for (gru = gru_base[bid]->bs_grus, chip = 0; + chip < GRU_CHIPLETS_PER_BLADE; + chip++, gru++) { + paddr = gru_chiplet_paddr(gru_base_paddr, pnode, chip); + vaddr = gru_chiplet_vaddr(gru_base_vaddr, pnode, chip); + gru_init_chiplet(gru, paddr, vaddr, bid, nid, chip); + n = hweight64(gru->gs_cbr_map) * GRU_CBR_AU_SIZE; + cbrs = max(cbrs, n); + n = hweight64(gru->gs_dsr_map) * GRU_DSR_AU_BYTES; + dsrbytes = max(dsrbytes, n); + } + max_user_cbrs = min(max_user_cbrs, cbrs); + max_user_dsr_bytes = min(max_user_dsr_bytes, dsrbytes); + } + + return 0; + +fail: + for (nid--; nid >= 0; nid--) + free_pages((unsigned long)gru_base[nid], order); + return -ENOMEM; +} + +#ifdef CONFIG_IA64 + +static int get_base_irq(void) +{ + return IRQ_GRU; +} + +#elif defined CONFIG_X86_64 + +static void noop(unsigned int irq) +{ +} + +static struct irq_chip gru_chip = { + .name = "gru", + .mask = noop, + .unmask = noop, + .ack = noop, +}; + +static int get_base_irq(void) +{ + set_irq_chip(IRQ_GRU, &gru_chip); + set_irq_chip(IRQ_GRU + 1, &gru_chip); + return IRQ_GRU; +} +#endif + +/* + * gru_init + * + * Called at boot or module load time to initialize the GRUs. + */ +static int __init gru_init(void) +{ + int ret, irq, chip; + char id[10]; + void *gru_start_vaddr; + + if (!IS_UV()) + return 0; + +#if defined CONFIG_IA64 + gru_start_paddr = 0xd000000000UL; /* ZZZZZZZZZZZZZZZZZZZ fixme */ +#else + gru_start_paddr = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR) & + 0x7fffffffffffUL; + +#endif + gru_start_vaddr = __va(gru_start_paddr); + gru_end_paddr = gru_start_paddr + MAX_NUMNODES * GRU_SIZE; + printk(KERN_INFO "GRU space: 0x%lx - 0x%lx\n", + gru_start_paddr, gru_end_paddr); + irq = get_base_irq(); + for (chip = 0; chip < GRU_CHIPLETS_PER_BLADE; chip++) { + ret = request_irq(irq + chip, gru_intr, 0, id, NULL); + if (ret) { + printk(KERN_ERR "%s: request_irq failed\n", + GRU_DRIVER_ID_STR); + goto exit1; + } + } + + ret = misc_register(&gru_miscdev); + if (ret) { + printk(KERN_ERR "%s: misc_register failed\n", + GRU_DRIVER_ID_STR); + goto exit1; + } + + ret = gru_proc_init(); + if (ret) { + printk(KERN_ERR "%s: proc init failed\n", GRU_DRIVER_ID_STR); + goto exit2; + } + + ret = gru_init_tables(gru_start_paddr, gru_start_vaddr); + if (ret) { + printk(KERN_ERR "%s: init tables failed\n", GRU_DRIVER_ID_STR); + goto exit3; + } + + printk(KERN_INFO "%s: v%s\n", GRU_DRIVER_ID_STR, + GRU_DRIVER_VERSION_STR); + return 0; + +exit3: + gru_proc_exit(); +exit2: + misc_deregister(&gru_miscdev); +exit1: + for (--chip; chip >= 0; chip--) + free_irq(irq + chip, NULL); + return ret; + +} + +static void __exit gru_exit(void) +{ + int i, bid; + int order = get_order(sizeof(struct gru_state) * + GRU_CHIPLETS_PER_BLADE); + + for (i = 0; i < GRU_CHIPLETS_PER_BLADE; i++) + free_irq(IRQ_GRU + i, NULL); + + for (bid = 0; bid < GRU_MAX_BLADES; bid++) + free_pages((unsigned long)gru_base[bid], order); + + misc_deregister(&gru_miscdev); + gru_proc_exit(); +} + +static struct file_operations gru_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = gru_file_unlocked_ioctl, + .mmap = gru_file_mmap, +}; + +static struct miscdevice gru_miscdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "gru", + .fops = &gru_fops, +}; + +struct vm_operations_struct gru_vm_ops = { + .close = gru_vma_close, + .fault = gru_fault, +}; + +module_init(gru_init); +module_exit(gru_exit); + +module_param(options, ulong, 0644); +MODULE_PARM_DESC(options, "Various debug options"); + +MODULE_AUTHOR("Silicon Graphics, Inc."); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(GRU_DRIVER_ID_STR GRU_DRIVER_VERSION_STR); +MODULE_VERSION(GRU_DRIVER_VERSION_STR); + -- cgit v1.2.3 From 142586409c8be7dc071bb94d7cd2d69ccfd99b6b Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Tue, 29 Jul 2008 22:33:57 -0700 Subject: GRU Driver: page faults & exceptions This file contains the functions that manage GRU page faults and exceptions. Signed-off-by: Jack Steiner Cc: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-gru/grufault.c | 633 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 633 insertions(+) create mode 100644 drivers/misc/sgi-gru/grufault.c (limited to 'drivers') diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c new file mode 100644 index 00000000000..3d33015bbf3 --- /dev/null +++ b/drivers/misc/sgi-gru/grufault.c @@ -0,0 +1,633 @@ +/* + * SN Platform GRU Driver + * + * FAULT HANDLER FOR GRU DETECTED TLB MISSES + * + * This file contains code that handles TLB misses within the GRU. + * These misses are reported either via interrupts or user polling of + * the user CB. + * + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gru.h" +#include "grutables.h" +#include "grulib.h" +#include "gru_instructions.h" +#include + +/* + * Test if a physical address is a valid GRU GSEG address + */ +static inline int is_gru_paddr(unsigned long paddr) +{ + return paddr >= gru_start_paddr && paddr < gru_end_paddr; +} + +/* + * Find the vma of a GRU segment. Caller must hold mmap_sem. + */ +struct vm_area_struct *gru_find_vma(unsigned long vaddr) +{ + struct vm_area_struct *vma; + + vma = find_vma(current->mm, vaddr); + if (vma && vma->vm_start <= vaddr && vma->vm_ops == &gru_vm_ops) + return vma; + return NULL; +} + +/* + * Find and lock the gts that contains the specified user vaddr. + * + * Returns: + * - *gts with the mmap_sem locked for read and the GTS locked. + * - NULL if vaddr invalid OR is not a valid GSEG vaddr. + */ + +static struct gru_thread_state *gru_find_lock_gts(unsigned long vaddr) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + struct gru_thread_state *gts = NULL; + + down_read(&mm->mmap_sem); + vma = gru_find_vma(vaddr); + if (vma) + gts = gru_find_thread_state(vma, TSID(vaddr, vma)); + if (gts) + mutex_lock(>s->ts_ctxlock); + else + up_read(&mm->mmap_sem); + return gts; +} + +static struct gru_thread_state *gru_alloc_locked_gts(unsigned long vaddr) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + struct gru_thread_state *gts = NULL; + + down_write(&mm->mmap_sem); + vma = gru_find_vma(vaddr); + if (vma) + gts = gru_alloc_thread_state(vma, TSID(vaddr, vma)); + if (gts) { + mutex_lock(>s->ts_ctxlock); + downgrade_write(&mm->mmap_sem); + } else { + up_write(&mm->mmap_sem); + } + + return gts; +} + +/* + * Unlock a GTS that was previously locked with gru_find_lock_gts(). + */ +static void gru_unlock_gts(struct gru_thread_state *gts) +{ + mutex_unlock(>s->ts_ctxlock); + up_read(¤t->mm->mmap_sem); +} + +/* + * Set a CB.istatus to active using a user virtual address. This must be done + * just prior to a TFH RESTART. The new cb.istatus is an in-cache status ONLY. + * If the line is evicted, the status may be lost. The in-cache update + * is necessary to prevent the user from seeing a stale cb.istatus that will + * change as soon as the TFH restart is complete. Races may cause an + * occasional failure to clear the cb.istatus, but that is ok. + * + * If the cb address is not valid (should not happen, but...), nothing + * bad will happen.. The get_user()/put_user() will fail but there + * are no bad side-effects. + */ +static void gru_cb_set_istatus_active(unsigned long __user *cb) +{ + union { + struct gru_instruction_bits bits; + unsigned long dw; + } u; + + if (cb) { + get_user(u.dw, cb); + u.bits.istatus = CBS_ACTIVE; + put_user(u.dw, cb); + } +} + +/* + * Convert a interrupt IRQ to a pointer to the GRU GTS that caused the + * interrupt. Interrupts are always sent to a cpu on the blade that contains the + * GRU (except for headless blades which are not currently supported). A blade + * has N grus; a block of N consecutive IRQs is assigned to the GRUs. The IRQ + * number uniquely identifies the GRU chiplet on the local blade that caused the + * interrupt. Always called in interrupt context. + */ +static inline struct gru_state *irq_to_gru(int irq) +{ + return &gru_base[uv_numa_blade_id()]->bs_grus[irq - IRQ_GRU]; +} + +/* + * Read & clear a TFM + * + * The GRU has an array of fault maps. A map is private to a cpu + * Only one cpu will be accessing a cpu's fault map. + * + * This function scans the cpu-private fault map & clears all bits that + * are set. The function returns a bitmap that indicates the bits that + * were cleared. Note that sense the maps may be updated asynchronously by + * the GRU, atomic operations must be used to clear bits. + */ +static void get_clear_fault_map(struct gru_state *gru, + struct gru_tlb_fault_map *map) +{ + unsigned long i, k; + struct gru_tlb_fault_map *tfm; + + tfm = get_tfm_for_cpu(gru, gru_cpu_fault_map_id()); + prefetchw(tfm); /* Helps on hardware, required for emulator */ + for (i = 0; i < BITS_TO_LONGS(GRU_NUM_CBE); i++) { + k = tfm->fault_bits[i]; + if (k) + k = xchg(&tfm->fault_bits[i], 0UL); + map->fault_bits[i] = k; + } + + /* + * Not functionally required but helps performance. (Required + * on emulator) + */ + gru_flush_cache(tfm); +} + +/* + * Atomic (interrupt context) & non-atomic (user context) functions to + * convert a vaddr into a physical address. The size of the page + * is returned in pageshift. + * returns: + * 0 - successful + * < 0 - error code + * 1 - (atomic only) try again in non-atomic context + */ +static int non_atomic_pte_lookup(struct vm_area_struct *vma, + unsigned long vaddr, int write, + unsigned long *paddr, int *pageshift) +{ + struct page *page; + + /* ZZZ Need to handle HUGE pages */ + if (is_vm_hugetlb_page(vma)) + return -EFAULT; + *pageshift = PAGE_SHIFT; + if (get_user_pages + (current, current->mm, vaddr, 1, write, 0, &page, NULL) <= 0) + return -EFAULT; + *paddr = page_to_phys(page); + put_page(page); + return 0; +} + +/* + * + * atomic_pte_lookup + * + * Convert a user virtual address to a physical address + * Only supports Intel large pages (2MB only) on x86_64. + * ZZZ - hugepage support is incomplete + */ +static int atomic_pte_lookup(struct vm_area_struct *vma, unsigned long vaddr, + int write, unsigned long *paddr, int *pageshift) +{ + pgd_t *pgdp; + pmd_t *pmdp; + pud_t *pudp; + pte_t pte; + + WARN_ON(irqs_disabled()); /* ZZZ debug */ + + local_irq_disable(); + pgdp = pgd_offset(vma->vm_mm, vaddr); + if (unlikely(pgd_none(*pgdp))) + goto err; + + pudp = pud_offset(pgdp, vaddr); + if (unlikely(pud_none(*pudp))) + goto err; + + pmdp = pmd_offset(pudp, vaddr); + if (unlikely(pmd_none(*pmdp))) + goto err; +#ifdef CONFIG_X86_64 + if (unlikely(pmd_large(*pmdp))) + pte = *(pte_t *) pmdp; + else +#endif + pte = *pte_offset_kernel(pmdp, vaddr); + + local_irq_enable(); + + if (unlikely(!pte_present(pte) || + (write && (!pte_write(pte) || !pte_dirty(pte))))) + return 1; + + *paddr = pte_pfn(pte) << PAGE_SHIFT; + *pageshift = is_vm_hugetlb_page(vma) ? HPAGE_SHIFT : PAGE_SHIFT; + return 0; + +err: + local_irq_enable(); + return 1; +} + +/* + * Drop a TLB entry into the GRU. The fault is described by info in an TFH. + * Input: + * cb Address of user CBR. Null if not running in user context + * Return: + * 0 = dropin, exception, or switch to UPM successful + * 1 = range invalidate active + * < 0 = error code + * + */ +static int gru_try_dropin(struct gru_thread_state *gts, + struct gru_tlb_fault_handle *tfh, + unsigned long __user *cb) +{ + struct mm_struct *mm = gts->ts_mm; + struct vm_area_struct *vma; + int pageshift, asid, write, ret; + unsigned long paddr, gpa, vaddr; + + /* + * NOTE: The GRU contains magic hardware that eliminates races between + * TLB invalidates and TLB dropins. If an invalidate occurs + * in the window between reading the TFH and the subsequent TLB dropin, + * the dropin is ignored. This eliminates the need for additional locks. + */ + + /* + * Error if TFH state is IDLE or FMM mode & the user issuing a UPM call. + * Might be a hardware race OR a stupid user. Ignore FMM because FMM + * is a transient state. + */ + if (tfh->state == TFHSTATE_IDLE) + goto failidle; + if (tfh->state == TFHSTATE_MISS_FMM && cb) + goto failfmm; + + write = (tfh->cause & TFHCAUSE_TLB_MOD) != 0; + vaddr = tfh->missvaddr; + asid = tfh->missasid; + if (asid == 0) + goto failnoasid; + + rmb(); /* TFH must be cache resident before reading ms_range_active */ + + /* + * TFH is cache resident - at least briefly. Fail the dropin + * if a range invalidate is active. + */ + if (atomic_read(>s->ts_gms->ms_range_active)) + goto failactive; + + vma = find_vma(mm, vaddr); + if (!vma) + goto failinval; + + /* + * Atomic lookup is faster & usually works even if called in non-atomic + * context. + */ + ret = atomic_pte_lookup(vma, vaddr, write, &paddr, &pageshift); + if (ret) { + if (!cb) + goto failupm; + if (non_atomic_pte_lookup(vma, vaddr, write, &paddr, + &pageshift)) + goto failinval; + } + if (is_gru_paddr(paddr)) + goto failinval; + + paddr = paddr & ~((1UL << pageshift) - 1); + gpa = uv_soc_phys_ram_to_gpa(paddr); + gru_cb_set_istatus_active(cb); + tfh_write_restart(tfh, gpa, GAA_RAM, vaddr, asid, write, + GRU_PAGESIZE(pageshift)); + STAT(tlb_dropin); + gru_dbg(grudev, + "%s: tfh 0x%p, vaddr 0x%lx, asid 0x%x, ps %d, gpa 0x%lx\n", + ret ? "non-atomic" : "atomic", tfh, vaddr, asid, + pageshift, gpa); + return 0; + +failnoasid: + /* No asid (delayed unload). */ + STAT(tlb_dropin_fail_no_asid); + gru_dbg(grudev, "FAILED no_asid tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr); + if (!cb) + tfh_user_polling_mode(tfh); + else + gru_flush_cache(tfh); + return -EAGAIN; + +failupm: + /* Atomic failure switch CBR to UPM */ + tfh_user_polling_mode(tfh); + STAT(tlb_dropin_fail_upm); + gru_dbg(grudev, "FAILED upm tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr); + return 1; + +failfmm: + /* FMM state on UPM call */ + STAT(tlb_dropin_fail_fmm); + gru_dbg(grudev, "FAILED fmm tfh: 0x%p, state %d\n", tfh, tfh->state); + return 0; + +failidle: + /* TFH was idle - no miss pending */ + gru_flush_cache(tfh); + if (cb) + gru_flush_cache(cb); + STAT(tlb_dropin_fail_idle); + gru_dbg(grudev, "FAILED idle tfh: 0x%p, state %d\n", tfh, tfh->state); + return 0; + +failinval: + /* All errors (atomic & non-atomic) switch CBR to EXCEPTION state */ + tfh_exception(tfh); + STAT(tlb_dropin_fail_invalid); + gru_dbg(grudev, "FAILED inval tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr); + return -EFAULT; + +failactive: + /* Range invalidate active. Switch to UPM iff atomic */ + if (!cb) + tfh_user_polling_mode(tfh); + else + gru_flush_cache(tfh); + STAT(tlb_dropin_fail_range_active); + gru_dbg(grudev, "FAILED range active: tfh 0x%p, vaddr 0x%lx\n", + tfh, vaddr); + return 1; +} + +/* + * Process an external interrupt from the GRU. This interrupt is + * caused by a TLB miss. + * Note that this is the interrupt handler that is registered with linux + * interrupt handlers. + */ +irqreturn_t gru_intr(int irq, void *dev_id) +{ + struct gru_state *gru; + struct gru_tlb_fault_map map; + struct gru_thread_state *gts; + struct gru_tlb_fault_handle *tfh = NULL; + int cbrnum, ctxnum; + + STAT(intr); + + gru = irq_to_gru(irq); + if (!gru) { + dev_err(grudev, "GRU: invalid interrupt: cpu %d, irq %d\n", + raw_smp_processor_id(), irq); + return IRQ_NONE; + } + get_clear_fault_map(gru, &map); + gru_dbg(grudev, "irq %d, gru %x, map 0x%lx\n", irq, gru->gs_gid, + map.fault_bits[0]); + + for_each_cbr_in_tfm(cbrnum, map.fault_bits) { + tfh = get_tfh_by_index(gru, cbrnum); + prefetchw(tfh); /* Helps on hdw, required for emulator */ + + /* + * When hardware sets a bit in the faultmap, it implicitly + * locks the GRU context so that it cannot be unloaded. + * The gts cannot change until a TFH start/writestart command + * is issued. + */ + ctxnum = tfh->ctxnum; + gts = gru->gs_gts[ctxnum]; + + /* + * This is running in interrupt context. Trylock the mmap_sem. + * If it fails, retry the fault in user context. + */ + if (down_read_trylock(>s->ts_mm->mmap_sem)) { + gru_try_dropin(gts, tfh, NULL); + up_read(>s->ts_mm->mmap_sem); + } else { + tfh_user_polling_mode(tfh); + } + } + return IRQ_HANDLED; +} + + +static int gru_user_dropin(struct gru_thread_state *gts, + struct gru_tlb_fault_handle *tfh, + unsigned long __user *cb) +{ + struct gru_mm_struct *gms = gts->ts_gms; + int ret; + + while (1) { + wait_event(gms->ms_wait_queue, + atomic_read(&gms->ms_range_active) == 0); + prefetchw(tfh); /* Helps on hdw, required for emulator */ + ret = gru_try_dropin(gts, tfh, cb); + if (ret <= 0) + return ret; + STAT(call_os_wait_queue); + } +} + +/* + * This interface is called as a result of a user detecting a "call OS" bit + * in a user CB. Normally means that a TLB fault has occurred. + * cb - user virtual address of the CB + */ +int gru_handle_user_call_os(unsigned long cb) +{ + struct gru_tlb_fault_handle *tfh; + struct gru_thread_state *gts; + unsigned long __user *cbp; + int ucbnum, cbrnum, ret = -EINVAL; + + STAT(call_os); + gru_dbg(grudev, "address 0x%lx\n", cb); + + /* sanity check the cb pointer */ + ucbnum = get_cb_number((void *)cb); + if ((cb & (GRU_HANDLE_STRIDE - 1)) || ucbnum >= GRU_NUM_CB) + return -EINVAL; + cbp = (unsigned long *)cb; + + gts = gru_find_lock_gts(cb); + if (!gts) + return -EINVAL; + + if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE) { + ret = -EINVAL; + goto exit; + } + + /* + * If force_unload is set, the UPM TLB fault is phony. The task + * has migrated to another node and the GSEG must be moved. Just + * unload the context. The task will page fault and assign a new + * context. + */ + ret = -EAGAIN; + cbrnum = thread_cbr_number(gts, ucbnum); + if (gts->ts_force_unload) { + gru_unload_context(gts, 1); + } else if (gts->ts_gru) { + tfh = get_tfh_by_index(gts->ts_gru, cbrnum); + ret = gru_user_dropin(gts, tfh, cbp); + } +exit: + gru_unlock_gts(gts); + return ret; +} + +/* + * Fetch the exception detail information for a CB that terminated with + * an exception. + */ +int gru_get_exception_detail(unsigned long arg) +{ + struct control_block_extended_exc_detail excdet; + struct gru_control_block_extended *cbe; + struct gru_thread_state *gts; + int ucbnum, cbrnum, ret; + + STAT(user_exception); + if (copy_from_user(&excdet, (void __user *)arg, sizeof(excdet))) + return -EFAULT; + + gru_dbg(grudev, "address 0x%lx\n", excdet.cb); + gts = gru_find_lock_gts(excdet.cb); + if (!gts) + return -EINVAL; + + if (gts->ts_gru) { + ucbnum = get_cb_number((void *)excdet.cb); + cbrnum = thread_cbr_number(gts, ucbnum); + cbe = get_cbe_by_index(gts->ts_gru, cbrnum); + excdet.opc = cbe->opccpy; + excdet.exopc = cbe->exopccpy; + excdet.ecause = cbe->ecause; + excdet.exceptdet0 = cbe->idef1upd; + excdet.exceptdet1 = cbe->idef3upd; + ret = 0; + } else { + ret = -EAGAIN; + } + gru_unlock_gts(gts); + + gru_dbg(grudev, "address 0x%lx, ecause 0x%x\n", excdet.cb, + excdet.ecause); + if (!ret && copy_to_user((void __user *)arg, &excdet, sizeof(excdet))) + ret = -EFAULT; + return ret; +} + +/* + * User request to unload a context. Content is saved for possible reload. + */ +int gru_user_unload_context(unsigned long arg) +{ + struct gru_thread_state *gts; + struct gru_unload_context_req req; + + STAT(user_unload_context); + if (copy_from_user(&req, (void __user *)arg, sizeof(req))) + return -EFAULT; + + gru_dbg(grudev, "gseg 0x%lx\n", req.gseg); + + gts = gru_find_lock_gts(req.gseg); + if (!gts) + return -EINVAL; + + if (gts->ts_gru) + gru_unload_context(gts, 1); + gru_unlock_gts(gts); + + return 0; +} + +/* + * User request to flush a range of virtual addresses from the GRU TLB + * (Mainly for testing). + */ +int gru_user_flush_tlb(unsigned long arg) +{ + struct gru_thread_state *gts; + struct gru_flush_tlb_req req; + + STAT(user_flush_tlb); + if (copy_from_user(&req, (void __user *)arg, sizeof(req))) + return -EFAULT; + + gru_dbg(grudev, "gseg 0x%lx, vaddr 0x%lx, len 0x%lx\n", req.gseg, + req.vaddr, req.len); + + gts = gru_find_lock_gts(req.gseg); + if (!gts) + return -EINVAL; + + gru_flush_tlb_range(gts->ts_gms, req.vaddr, req.vaddr + req.len); + gru_unlock_gts(gts); + + return 0; +} + +/* + * Register the current task as the user of the GSEG slice. + * Needed for TLB fault interrupt targeting. + */ +int gru_set_task_slice(long address) +{ + struct gru_thread_state *gts; + + STAT(set_task_slice); + gru_dbg(grudev, "address 0x%lx\n", address); + gts = gru_alloc_locked_gts(address); + if (!gts) + return -EINVAL; + + gts->ts_tgid_owner = current->tgid; + gru_unlock_gts(gts); + + return 0; +} -- cgit v1.2.3 From 28bffaf094a6d0992c85e1b01f04c9b0f56c9d62 Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Tue, 29 Jul 2008 22:33:57 -0700 Subject: GRU Driver: kernel services provide by driver This file contains functions for handling services provided to other kernel modules that use the GRU. Signed-off-by: Jack Steiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-gru/grukservices.c | 679 ++++++++++++++++++++++++++++++++++++ 1 file changed, 679 insertions(+) create mode 100644 drivers/misc/sgi-gru/grukservices.c (limited to 'drivers') diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c new file mode 100644 index 00000000000..234d165fb11 --- /dev/null +++ b/drivers/misc/sgi-gru/grukservices.c @@ -0,0 +1,679 @@ +/* + * SN Platform GRU Driver + * + * KERNEL SERVICES THAT USE THE GRU + * + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gru.h" +#include "grulib.h" +#include "grutables.h" +#include "grukservices.h" +#include "gru_instructions.h" +#include + +/* + * Kernel GRU Usage + * + * The following is an interim algorithm for management of kernel GRU + * resources. This will likely be replaced when we better understand the + * kernel/user requirements. + * + * At boot time, the kernel permanently reserves a fixed number of + * CBRs/DSRs for each cpu to use. The resources are all taken from + * the GRU chiplet 1 on the blade. This leaves the full set of resources + * of chiplet 0 available to be allocated to a single user. + */ + +/* Blade percpu resources PERMANENTLY reserved for kernel use */ +#define GRU_NUM_KERNEL_CBR 1 +#define GRU_NUM_KERNEL_DSR_BYTES 256 +#define KERNEL_CTXNUM 15 + +/* GRU instruction attributes for all instructions */ +#define IMA IMA_CB_DELAY + +/* GRU cacheline size is always 64 bytes - even on arches with 128 byte lines */ +#define __gru_cacheline_aligned__ \ + __attribute__((__aligned__(GRU_CACHE_LINE_BYTES))) + +#define MAGIC 0x1234567887654321UL + +/* Default retry count for GRU errors on kernel instructions */ +#define EXCEPTION_RETRY_LIMIT 3 + +/* Status of message queue sections */ +#define MQS_EMPTY 0 +#define MQS_FULL 1 +#define MQS_NOOP 2 + +/*----------------- RESOURCE MANAGEMENT -------------------------------------*/ +/* optimized for x86_64 */ +struct message_queue { + union gru_mesqhead head __gru_cacheline_aligned__; /* CL 0 */ + int qlines; /* DW 1 */ + long hstatus[2]; + void *next __gru_cacheline_aligned__;/* CL 1 */ + void *limit; + void *start; + void *start2; + char data ____cacheline_aligned; /* CL 2 */ +}; + +/* First word in every message - used by mesq interface */ +struct message_header { + char present; + char present2; + char lines; + char fill; +}; + +#define QLINES(mq) ((mq) + offsetof(struct message_queue, qlines)) +#define HSTATUS(mq, h) ((mq) + offsetof(struct message_queue, hstatus[h])) + +static int gru_get_cpu_resources(int dsr_bytes, void **cb, void **dsr) +{ + struct gru_blade_state *bs; + int lcpu; + + BUG_ON(dsr_bytes > GRU_NUM_KERNEL_DSR_BYTES); + preempt_disable(); + bs = gru_base[uv_numa_blade_id()]; + lcpu = uv_blade_processor_id(); + *cb = bs->kernel_cb + lcpu * GRU_HANDLE_STRIDE; + *dsr = bs->kernel_dsr + lcpu * GRU_NUM_KERNEL_DSR_BYTES; + return 0; +} + +static void gru_free_cpu_resources(void *cb, void *dsr) +{ + preempt_enable(); +} + +int gru_get_cb_exception_detail(void *cb, + struct control_block_extended_exc_detail *excdet) +{ + struct gru_control_block_extended *cbe; + + cbe = get_cbe(GRUBASE(cb), get_cb_number(cb)); + excdet->opc = cbe->opccpy; + excdet->exopc = cbe->exopccpy; + excdet->ecause = cbe->ecause; + excdet->exceptdet0 = cbe->idef1upd; + excdet->exceptdet1 = cbe->idef3upd; + return 0; +} + +char *gru_get_cb_exception_detail_str(int ret, void *cb, + char *buf, int size) +{ + struct gru_control_block_status *gen = (void *)cb; + struct control_block_extended_exc_detail excdet; + + if (ret > 0 && gen->istatus == CBS_EXCEPTION) { + gru_get_cb_exception_detail(cb, &excdet); + snprintf(buf, size, + "GRU exception: cb %p, opc %d, exopc %d, ecause 0x%x," + "excdet0 0x%lx, excdet1 0x%x", + gen, excdet.opc, excdet.exopc, excdet.ecause, + excdet.exceptdet0, excdet.exceptdet1); + } else { + snprintf(buf, size, "No exception"); + } + return buf; +} + +static int gru_wait_idle_or_exception(struct gru_control_block_status *gen) +{ + while (gen->istatus >= CBS_ACTIVE) { + cpu_relax(); + barrier(); + } + return gen->istatus; +} + +static int gru_retry_exception(void *cb) +{ + struct gru_control_block_status *gen = (void *)cb; + struct control_block_extended_exc_detail excdet; + int retry = EXCEPTION_RETRY_LIMIT; + + while (1) { + if (gru_get_cb_message_queue_substatus(cb)) + break; + if (gru_wait_idle_or_exception(gen) == CBS_IDLE) + return CBS_IDLE; + + gru_get_cb_exception_detail(cb, &excdet); + if (excdet.ecause & ~EXCEPTION_RETRY_BITS) + break; + if (retry-- == 0) + break; + gen->icmd = 1; + gru_flush_cache(gen); + } + return CBS_EXCEPTION; +} + +int gru_check_status_proc(void *cb) +{ + struct gru_control_block_status *gen = (void *)cb; + int ret; + + ret = gen->istatus; + if (ret != CBS_EXCEPTION) + return ret; + return gru_retry_exception(cb); + +} + +int gru_wait_proc(void *cb) +{ + struct gru_control_block_status *gen = (void *)cb; + int ret; + + ret = gru_wait_idle_or_exception(gen); + if (ret == CBS_EXCEPTION) + ret = gru_retry_exception(cb); + + return ret; +} + +void gru_abort(int ret, void *cb, char *str) +{ + char buf[GRU_EXC_STR_SIZE]; + + panic("GRU FATAL ERROR: %s - %s\n", str, + gru_get_cb_exception_detail_str(ret, cb, buf, sizeof(buf))); +} + +void gru_wait_abort_proc(void *cb) +{ + int ret; + + ret = gru_wait_proc(cb); + if (ret) + gru_abort(ret, cb, "gru_wait_abort"); +} + + +/*------------------------------ MESSAGE QUEUES -----------------------------*/ + +/* Internal status . These are NOT returned to the user. */ +#define MQIE_AGAIN -1 /* try again */ + + +/* + * Save/restore the "present" flag that is in the second line of 2-line + * messages + */ +static inline int get_present2(void *p) +{ + struct message_header *mhdr = p + GRU_CACHE_LINE_BYTES; + return mhdr->present; +} + +static inline void restore_present2(void *p, int val) +{ + struct message_header *mhdr = p + GRU_CACHE_LINE_BYTES; + mhdr->present = val; +} + +/* + * Create a message queue. + * qlines - message queue size in cache lines. Includes 2-line header. + */ +int gru_create_message_queue(void *p, unsigned int bytes) +{ + struct message_queue *mq = p; + unsigned int qlines; + + qlines = bytes / GRU_CACHE_LINE_BYTES - 2; + memset(mq, 0, bytes); + mq->start = &mq->data; + mq->start2 = &mq->data + (qlines / 2 - 1) * GRU_CACHE_LINE_BYTES; + mq->next = &mq->data; + mq->limit = &mq->data + (qlines - 2) * GRU_CACHE_LINE_BYTES; + mq->qlines = qlines; + mq->hstatus[0] = 0; + mq->hstatus[1] = 1; + mq->head = gru_mesq_head(2, qlines / 2 + 1); + return 0; +} +EXPORT_SYMBOL_GPL(gru_create_message_queue); + +/* + * Send a NOOP message to a message queue + * Returns: + * 0 - if queue is full after the send. This is the normal case + * but various races can change this. + * -1 - if mesq sent successfully but queue not full + * >0 - unexpected error. MQE_xxx returned + */ +static int send_noop_message(void *cb, + unsigned long mq, void *mesg) +{ + const struct message_header noop_header = { + .present = MQS_NOOP, .lines = 1}; + unsigned long m; + int substatus, ret; + struct message_header save_mhdr, *mhdr = mesg; + + STAT(mesq_noop); + save_mhdr = *mhdr; + *mhdr = noop_header; + gru_mesq(cb, mq, gru_get_tri(mhdr), 1, IMA); + ret = gru_wait(cb); + + if (ret) { + substatus = gru_get_cb_message_queue_substatus(cb); + switch (substatus) { + case CBSS_NO_ERROR: + STAT(mesq_noop_unexpected_error); + ret = MQE_UNEXPECTED_CB_ERR; + break; + case CBSS_LB_OVERFLOWED: + STAT(mesq_noop_lb_overflow); + ret = MQE_CONGESTION; + break; + case CBSS_QLIMIT_REACHED: + STAT(mesq_noop_qlimit_reached); + ret = 0; + break; + case CBSS_AMO_NACKED: + STAT(mesq_noop_amo_nacked); + ret = MQE_CONGESTION; + break; + case CBSS_PUT_NACKED: + STAT(mesq_noop_put_nacked); + m = mq + (gru_get_amo_value_head(cb) << 6); + gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, 1, 1, + IMA); + if (gru_wait(cb) == CBS_IDLE) + ret = MQIE_AGAIN; + else + ret = MQE_UNEXPECTED_CB_ERR; + break; + case CBSS_PAGE_OVERFLOW: + default: + BUG(); + } + } + *mhdr = save_mhdr; + return ret; +} + +/* + * Handle a gru_mesq full. + */ +static int send_message_queue_full(void *cb, + unsigned long mq, void *mesg, int lines) +{ + union gru_mesqhead mqh; + unsigned int limit, head; + unsigned long avalue; + int half, qlines, save; + + /* Determine if switching to first/second half of q */ + avalue = gru_get_amo_value(cb); + head = gru_get_amo_value_head(cb); + limit = gru_get_amo_value_limit(cb); + + /* + * Fetch "qlines" from the queue header. Since the queue may be + * in memory that can't be accessed using socket addresses, use + * the GRU to access the data. Use DSR space from the message. + */ + save = *(int *)mesg; + gru_vload(cb, QLINES(mq), gru_get_tri(mesg), XTYPE_W, 1, 1, IMA); + if (gru_wait(cb) != CBS_IDLE) + goto cberr; + qlines = *(int *)mesg; + *(int *)mesg = save; + half = (limit != qlines); + + if (half) + mqh = gru_mesq_head(qlines / 2 + 1, qlines); + else + mqh = gru_mesq_head(2, qlines / 2 + 1); + + /* Try to get lock for switching head pointer */ + gru_gamir(cb, EOP_IR_CLR, HSTATUS(mq, half), XTYPE_DW, IMA); + if (gru_wait(cb) != CBS_IDLE) + goto cberr; + if (!gru_get_amo_value(cb)) { + STAT(mesq_qf_locked); + return MQE_QUEUE_FULL; + } + + /* Got the lock. Send optional NOP if queue not full, */ + if (head != limit) { + if (send_noop_message(cb, mq, mesg)) { + gru_gamir(cb, EOP_IR_INC, HSTATUS(mq, half), + XTYPE_DW, IMA); + if (gru_wait(cb) != CBS_IDLE) + goto cberr; + STAT(mesq_qf_noop_not_full); + return MQIE_AGAIN; + } + avalue++; + } + + /* Then flip queuehead to other half of queue. */ + gru_gamer(cb, EOP_ERR_CSWAP, mq, XTYPE_DW, mqh.val, avalue, IMA); + if (gru_wait(cb) != CBS_IDLE) + goto cberr; + + /* If not successfully in swapping queue head, clear the hstatus lock */ + if (gru_get_amo_value(cb) != avalue) { + STAT(mesq_qf_switch_head_failed); + gru_gamir(cb, EOP_IR_INC, HSTATUS(mq, half), XTYPE_DW, IMA); + if (gru_wait(cb) != CBS_IDLE) + goto cberr; + } + return MQIE_AGAIN; +cberr: + STAT(mesq_qf_unexpected_error); + return MQE_UNEXPECTED_CB_ERR; +} + + +/* + * Handle a gru_mesq failure. Some of these failures are software recoverable + * or retryable. + */ +static int send_message_failure(void *cb, + unsigned long mq, + void *mesg, + int lines) +{ + int substatus, ret = 0; + unsigned long m; + + substatus = gru_get_cb_message_queue_substatus(cb); + switch (substatus) { + case CBSS_NO_ERROR: + STAT(mesq_send_unexpected_error); + ret = MQE_UNEXPECTED_CB_ERR; + break; + case CBSS_LB_OVERFLOWED: + STAT(mesq_send_lb_overflow); + ret = MQE_CONGESTION; + break; + case CBSS_QLIMIT_REACHED: + STAT(mesq_send_qlimit_reached); + ret = send_message_queue_full(cb, mq, mesg, lines); + break; + case CBSS_AMO_NACKED: + STAT(mesq_send_amo_nacked); + ret = MQE_CONGESTION; + break; + case CBSS_PUT_NACKED: + STAT(mesq_send_put_nacked); + m =mq + (gru_get_amo_value_head(cb) << 6); + gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA); + if (gru_wait(cb) == CBS_IDLE) + ret = MQE_OK; + else + ret = MQE_UNEXPECTED_CB_ERR; + break; + default: + BUG(); + } + return ret; +} + +/* + * Send a message to a message queue + * cb GRU control block to use to send message + * mq message queue + * mesg message. ust be vaddr within a GSEG + * bytes message size (<= 2 CL) + */ +int gru_send_message_gpa(unsigned long mq, void *mesg, unsigned int bytes) +{ + struct message_header *mhdr; + void *cb; + void *dsr; + int istatus, clines, ret; + + STAT(mesq_send); + BUG_ON(bytes < sizeof(int) || bytes > 2 * GRU_CACHE_LINE_BYTES); + + clines = (bytes + GRU_CACHE_LINE_BYTES - 1) / GRU_CACHE_LINE_BYTES; + if (gru_get_cpu_resources(bytes, &cb, &dsr)) + return MQE_BUG_NO_RESOURCES; + memcpy(dsr, mesg, bytes); + mhdr = dsr; + mhdr->present = MQS_FULL; + mhdr->lines = clines; + if (clines == 2) { + mhdr->present2 = get_present2(mhdr); + restore_present2(mhdr, MQS_FULL); + } + + do { + ret = MQE_OK; + gru_mesq(cb, mq, gru_get_tri(mhdr), clines, IMA); + istatus = gru_wait(cb); + if (istatus != CBS_IDLE) + ret = send_message_failure(cb, mq, dsr, clines); + } while (ret == MQIE_AGAIN); + gru_free_cpu_resources(cb, dsr); + + if (ret) + STAT(mesq_send_failed); + return ret; +} +EXPORT_SYMBOL_GPL(gru_send_message_gpa); + +/* + * Advance the receive pointer for the queue to the next message. + */ +void gru_free_message(void *rmq, void *mesg) +{ + struct message_queue *mq = rmq; + struct message_header *mhdr = mq->next; + void *next, *pnext; + int half = -1; + int lines = mhdr->lines; + + if (lines == 2) + restore_present2(mhdr, MQS_EMPTY); + mhdr->present = MQS_EMPTY; + + pnext = mq->next; + next = pnext + GRU_CACHE_LINE_BYTES * lines; + if (next == mq->limit) { + next = mq->start; + half = 1; + } else if (pnext < mq->start2 && next >= mq->start2) { + half = 0; + } + + if (half >= 0) + mq->hstatus[half] = 1; + mq->next = next; +} +EXPORT_SYMBOL_GPL(gru_free_message); + +/* + * Get next message from message queue. Return NULL if no message + * present. User must call next_message() to move to next message. + * rmq message queue + */ +void *gru_get_next_message(void *rmq) +{ + struct message_queue *mq = rmq; + struct message_header *mhdr = mq->next; + int present = mhdr->present; + + /* skip NOOP messages */ + STAT(mesq_receive); + while (present == MQS_NOOP) { + gru_free_message(rmq, mhdr); + mhdr = mq->next; + present = mhdr->present; + } + + /* Wait for both halves of 2 line messages */ + if (present == MQS_FULL && mhdr->lines == 2 && + get_present2(mhdr) == MQS_EMPTY) + present = MQS_EMPTY; + + if (!present) { + STAT(mesq_receive_none); + return NULL; + } + + if (mhdr->lines == 2) + restore_present2(mhdr, mhdr->present2); + + return mhdr; +} +EXPORT_SYMBOL_GPL(gru_get_next_message); + +/* ---------------------- GRU DATA COPY FUNCTIONS ---------------------------*/ + +/* + * Copy a block of data using the GRU resources + */ +int gru_copy_gpa(unsigned long dest_gpa, unsigned long src_gpa, + unsigned int bytes) +{ + void *cb; + void *dsr; + int ret; + + STAT(copy_gpa); + if (gru_get_cpu_resources(GRU_NUM_KERNEL_DSR_BYTES, &cb, &dsr)) + return MQE_BUG_NO_RESOURCES; + gru_bcopy(cb, src_gpa, dest_gpa, gru_get_tri(dsr), + XTYPE_B, bytes, GRU_NUM_KERNEL_DSR_BYTES, IMA); + ret = gru_wait(cb); + gru_free_cpu_resources(cb, dsr); + return ret; +} +EXPORT_SYMBOL_GPL(gru_copy_gpa); + +/* ------------------- KERNEL QUICKTESTS RUN AT STARTUP ----------------*/ +/* Temp - will delete after we gain confidence in the GRU */ +static __cacheline_aligned unsigned long word0; +static __cacheline_aligned unsigned long word1; + +static int quicktest(struct gru_state *gru) +{ + void *cb; + void *ds; + unsigned long *p; + + cb = get_gseg_base_address_cb(gru->gs_gru_base_vaddr, KERNEL_CTXNUM, 0); + ds = get_gseg_base_address_ds(gru->gs_gru_base_vaddr, KERNEL_CTXNUM, 0); + p = ds; + word0 = MAGIC; + + gru_vload(cb, uv_gpa(&word0), 0, XTYPE_DW, 1, 1, IMA); + if (gru_wait(cb) != CBS_IDLE) + BUG(); + + if (*(unsigned long *)ds != MAGIC) + BUG(); + gru_vstore(cb, uv_gpa(&word1), 0, XTYPE_DW, 1, 1, IMA); + if (gru_wait(cb) != CBS_IDLE) + BUG(); + + if (word0 != word1 || word0 != MAGIC) { + printk + ("GRU quicktest err: gru %d, found 0x%lx, expected 0x%lx\n", + gru->gs_gid, word1, MAGIC); + BUG(); /* ZZZ should not be fatal */ + } + + return 0; +} + + +int gru_kservices_init(struct gru_state *gru) +{ + struct gru_blade_state *bs; + struct gru_context_configuration_handle *cch; + unsigned long cbr_map, dsr_map; + int err, num, cpus_possible; + + /* + * Currently, resources are reserved ONLY on the second chiplet + * on each blade. This leaves ALL resources on chiplet 0 available + * for user code. + */ + bs = gru->gs_blade; + if (gru != &bs->bs_grus[1]) + return 0; + + cpus_possible = uv_blade_nr_possible_cpus(gru->gs_blade_id); + + num = GRU_NUM_KERNEL_CBR * cpus_possible; + cbr_map = reserve_gru_cb_resources(gru, GRU_CB_COUNT_TO_AU(num), NULL); + gru->gs_reserved_cbrs += num; + + num = GRU_NUM_KERNEL_DSR_BYTES * cpus_possible; + dsr_map = reserve_gru_ds_resources(gru, GRU_DS_BYTES_TO_AU(num), NULL); + gru->gs_reserved_dsr_bytes += num; + + gru->gs_active_contexts++; + __set_bit(KERNEL_CTXNUM, &gru->gs_context_map); + cch = get_cch(gru->gs_gru_base_vaddr, KERNEL_CTXNUM); + + bs->kernel_cb = get_gseg_base_address_cb(gru->gs_gru_base_vaddr, + KERNEL_CTXNUM, 0); + bs->kernel_dsr = get_gseg_base_address_ds(gru->gs_gru_base_vaddr, + KERNEL_CTXNUM, 0); + + lock_cch_handle(cch); + cch->tfm_fault_bit_enable = 0; + cch->tlb_int_enable = 0; + cch->tfm_done_bit_enable = 0; + cch->unmap_enable = 1; + err = cch_allocate(cch, 0, cbr_map, dsr_map); + if (err) { + gru_dbg(grudev, + "Unable to allocate kernel CCH: gru %d, err %d\n", + gru->gs_gid, err); + BUG(); + } + if (cch_start(cch)) { + gru_dbg(grudev, "Unable to start kernel CCH: gru %d, err %d\n", + gru->gs_gid, err); + BUG(); + } + unlock_cch_handle(cch); + + if (options & GRU_QUICKLOOK) + quicktest(gru); + return 0; +} -- cgit v1.2.3 From 9a0deecc90de62c91d7107611446c0c950091851 Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Tue, 29 Jul 2008 22:33:58 -0700 Subject: GRU Driver: resource management This file contains functions realted to managing GRU resources provided to the user. Examples include GRU context assignment, load, unload, migration, etc.. Signed-off-by: Jack Steiner Cc: Nick Piggin Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-gru/grumain.c | 798 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 798 insertions(+) create mode 100644 drivers/misc/sgi-gru/grumain.c (limited to 'drivers') diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c new file mode 100644 index 00000000000..aef6822cb80 --- /dev/null +++ b/drivers/misc/sgi-gru/grumain.c @@ -0,0 +1,798 @@ +/* + * SN Platform GRU Driver + * + * DRIVER TABLE MANAGER + GRU CONTEXT LOAD/UNLOAD + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "gru.h" +#include "grutables.h" +#include "gruhandles.h" + +unsigned long options __read_mostly; + +static struct device_driver gru_driver = { + .name = "gru" +}; + +static struct device gru_device = { + .bus_id = {0}, + .driver = &gru_driver, +}; + +struct device *grudev = &gru_device; + +/* + * Select a gru fault map to be used by the current cpu. Note that + * multiple cpus may be using the same map. + * ZZZ should "shift" be used?? Depends on HT cpu numbering + * ZZZ should be inline but did not work on emulator + */ +int gru_cpu_fault_map_id(void) +{ + return uv_blade_processor_id() % GRU_NUM_TFM; +} + +/*--------- ASID Management ------------------------------------------- + * + * Initially, assign asids sequentially from MIN_ASID .. MAX_ASID. + * Once MAX is reached, flush the TLB & start over. However, + * some asids may still be in use. There won't be many (percentage wise) still + * in use. Search active contexts & determine the value of the first + * asid in use ("x"s below). Set "limit" to this value. + * This defines a block of assignable asids. + * + * When "limit" is reached, search forward from limit+1 and determine the + * next block of assignable asids. + * + * Repeat until MAX_ASID is reached, then start over again. + * + * Each time MAX_ASID is reached, increment the asid generation. Since + * the search for in-use asids only checks contexts with GRUs currently + * assigned, asids in some contexts will be missed. Prior to loading + * a context, the asid generation of the GTS asid is rechecked. If it + * doesn't match the current generation, a new asid will be assigned. + * + * 0---------------x------------x---------------------x----| + * ^-next ^-limit ^-MAX_ASID + * + * All asid manipulation & context loading/unloading is protected by the + * gs_lock. + */ + +/* Hit the asid limit. Start over */ +static int gru_wrap_asid(struct gru_state *gru) +{ + gru_dbg(grudev, "gru %p\n", gru); + STAT(asid_wrap); + gru->gs_asid_gen++; + gru_flush_all_tlb(gru); + return MIN_ASID; +} + +/* Find the next chunk of unused asids */ +static int gru_reset_asid_limit(struct gru_state *gru, int asid) +{ + int i, gid, inuse_asid, limit; + + gru_dbg(grudev, "gru %p, asid 0x%x\n", gru, asid); + STAT(asid_next); + limit = MAX_ASID; + if (asid >= limit) + asid = gru_wrap_asid(gru); + gid = gru->gs_gid; +again: + for (i = 0; i < GRU_NUM_CCH; i++) { + if (!gru->gs_gts[i]) + continue; + inuse_asid = gru->gs_gts[i]->ts_gms->ms_asids[gid].mt_asid; + gru_dbg(grudev, "gru %p, inuse_asid 0x%x, cxtnum %d, gts %p\n", + gru, inuse_asid, i, gru->gs_gts[i]); + if (inuse_asid == asid) { + asid += ASID_INC; + if (asid >= limit) { + /* + * empty range: reset the range limit and + * start over + */ + limit = MAX_ASID; + if (asid >= MAX_ASID) + asid = gru_wrap_asid(gru); + goto again; + } + } + + if ((inuse_asid > asid) && (inuse_asid < limit)) + limit = inuse_asid; + } + gru->gs_asid_limit = limit; + gru->gs_asid = asid; + gru_dbg(grudev, "gru %p, new asid 0x%x, new_limit 0x%x\n", gru, asid, + limit); + return asid; +} + +/* Assign a new ASID to a thread context. */ +static int gru_assign_asid(struct gru_state *gru) +{ + int asid; + + spin_lock(&gru->gs_asid_lock); + gru->gs_asid += ASID_INC; + asid = gru->gs_asid; + if (asid >= gru->gs_asid_limit) + asid = gru_reset_asid_limit(gru, asid); + spin_unlock(&gru->gs_asid_lock); + + gru_dbg(grudev, "gru %p, asid 0x%x\n", gru, asid); + return asid; +} + +/* + * Clear n bits in a word. Return a word indicating the bits that were cleared. + * Optionally, build an array of chars that contain the bit numbers allocated. + */ +static unsigned long reserve_resources(unsigned long *p, int n, int mmax, + char *idx) +{ + unsigned long bits = 0; + int i; + + do { + i = find_first_bit(p, mmax); + if (i == mmax) + BUG(); + __clear_bit(i, p); + __set_bit(i, &bits); + if (idx) + *idx++ = i; + } while (--n); + return bits; +} + +unsigned long reserve_gru_cb_resources(struct gru_state *gru, int cbr_au_count, + char *cbmap) +{ + return reserve_resources(&gru->gs_cbr_map, cbr_au_count, GRU_CBR_AU, + cbmap); +} + +unsigned long reserve_gru_ds_resources(struct gru_state *gru, int dsr_au_count, + char *dsmap) +{ + return reserve_resources(&gru->gs_dsr_map, dsr_au_count, GRU_DSR_AU, + dsmap); +} + +static void reserve_gru_resources(struct gru_state *gru, + struct gru_thread_state *gts) +{ + gru->gs_active_contexts++; + gts->ts_cbr_map = + reserve_gru_cb_resources(gru, gts->ts_cbr_au_count, + gts->ts_cbr_idx); + gts->ts_dsr_map = + reserve_gru_ds_resources(gru, gts->ts_dsr_au_count, NULL); +} + +static void free_gru_resources(struct gru_state *gru, + struct gru_thread_state *gts) +{ + gru->gs_active_contexts--; + gru->gs_cbr_map |= gts->ts_cbr_map; + gru->gs_dsr_map |= gts->ts_dsr_map; +} + +/* + * Check if a GRU has sufficient free resources to satisfy an allocation + * request. Note: GRU locks may or may not be held when this is called. If + * not held, recheck after acquiring the appropriate locks. + * + * Returns 1 if sufficient resources, 0 if not + */ +static int check_gru_resources(struct gru_state *gru, int cbr_au_count, + int dsr_au_count, int max_active_contexts) +{ + return hweight64(gru->gs_cbr_map) >= cbr_au_count + && hweight64(gru->gs_dsr_map) >= dsr_au_count + && gru->gs_active_contexts < max_active_contexts; +} + +/* + * TLB manangment requires tracking all GRU chiplets that have loaded a GSEG + * context. + */ +static int gru_load_mm_tracker(struct gru_state *gru, struct gru_mm_struct *gms, + int ctxnum) +{ + struct gru_mm_tracker *asids = &gms->ms_asids[gru->gs_gid]; + unsigned short ctxbitmap = (1 << ctxnum); + int asid; + + spin_lock(&gms->ms_asid_lock); + asid = asids->mt_asid; + + if (asid == 0 || asids->mt_asid_gen != gru->gs_asid_gen) { + asid = gru_assign_asid(gru); + asids->mt_asid = asid; + asids->mt_asid_gen = gru->gs_asid_gen; + STAT(asid_new); + } else { + STAT(asid_reuse); + } + + BUG_ON(asids->mt_ctxbitmap & ctxbitmap); + asids->mt_ctxbitmap |= ctxbitmap; + if (!test_bit(gru->gs_gid, gms->ms_asidmap)) + __set_bit(gru->gs_gid, gms->ms_asidmap); + spin_unlock(&gms->ms_asid_lock); + + gru_dbg(grudev, + "gru %x, gms %p, ctxnum 0x%d, asid 0x%x, asidmap 0x%lx\n", + gru->gs_gid, gms, ctxnum, asid, gms->ms_asidmap[0]); + return asid; +} + +static void gru_unload_mm_tracker(struct gru_state *gru, + struct gru_mm_struct *gms, int ctxnum) +{ + struct gru_mm_tracker *asids; + unsigned short ctxbitmap; + + asids = &gms->ms_asids[gru->gs_gid]; + ctxbitmap = (1 << ctxnum); + spin_lock(&gms->ms_asid_lock); + BUG_ON((asids->mt_ctxbitmap & ctxbitmap) != ctxbitmap); + asids->mt_ctxbitmap ^= ctxbitmap; + gru_dbg(grudev, "gru %x, gms %p, ctxnum 0x%d, asidmap 0x%lx\n", + gru->gs_gid, gms, ctxnum, gms->ms_asidmap[0]); + spin_unlock(&gms->ms_asid_lock); +} + +/* + * Decrement the reference count on a GTS structure. Free the structure + * if the reference count goes to zero. + */ +void gts_drop(struct gru_thread_state *gts) +{ + if (gts && atomic_dec_return(>s->ts_refcnt) == 0) { + gru_drop_mmu_notifier(gts->ts_gms); + kfree(gts); + STAT(gts_free); + } +} + +/* + * Locate the GTS structure for the current thread. + */ +static struct gru_thread_state *gru_find_current_gts_nolock(struct gru_vma_data + *vdata, int tsid) +{ + struct gru_thread_state *gts; + + list_for_each_entry(gts, &vdata->vd_head, ts_next) + if (gts->ts_tsid == tsid) + return gts; + return NULL; +} + +/* + * Allocate a thread state structure. + */ +static struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, + struct gru_vma_data *vdata, + int tsid) +{ + struct gru_thread_state *gts; + int bytes; + + bytes = DSR_BYTES(vdata->vd_dsr_au_count) + + CBR_BYTES(vdata->vd_cbr_au_count); + bytes += sizeof(struct gru_thread_state); + gts = kzalloc(bytes, GFP_KERNEL); + if (!gts) + return NULL; + + STAT(gts_alloc); + atomic_set(>s->ts_refcnt, 1); + mutex_init(>s->ts_ctxlock); + gts->ts_cbr_au_count = vdata->vd_cbr_au_count; + gts->ts_dsr_au_count = vdata->vd_dsr_au_count; + gts->ts_user_options = vdata->vd_user_options; + gts->ts_tsid = tsid; + gts->ts_user_options = vdata->vd_user_options; + gts->ts_ctxnum = NULLCTX; + gts->ts_mm = current->mm; + gts->ts_vma = vma; + gts->ts_tlb_int_select = -1; + gts->ts_gms = gru_register_mmu_notifier(); + if (!gts->ts_gms) + goto err; + + gru_dbg(grudev, "alloc vdata %p, new gts %p\n", vdata, gts); + return gts; + +err: + gts_drop(gts); + return NULL; +} + +/* + * Allocate a vma private data structure. + */ +struct gru_vma_data *gru_alloc_vma_data(struct vm_area_struct *vma, int tsid) +{ + struct gru_vma_data *vdata = NULL; + + vdata = kmalloc(sizeof(*vdata), GFP_KERNEL); + if (!vdata) + return NULL; + + INIT_LIST_HEAD(&vdata->vd_head); + spin_lock_init(&vdata->vd_lock); + gru_dbg(grudev, "alloc vdata %p\n", vdata); + return vdata; +} + +/* + * Find the thread state structure for the current thread. + */ +struct gru_thread_state *gru_find_thread_state(struct vm_area_struct *vma, + int tsid) +{ + struct gru_vma_data *vdata = vma->vm_private_data; + struct gru_thread_state *gts; + + spin_lock(&vdata->vd_lock); + gts = gru_find_current_gts_nolock(vdata, tsid); + spin_unlock(&vdata->vd_lock); + gru_dbg(grudev, "vma %p, gts %p\n", vma, gts); + return gts; +} + +/* + * Allocate a new thread state for a GSEG. Note that races may allow + * another thread to race to create a gts. + */ +struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct *vma, + int tsid) +{ + struct gru_vma_data *vdata = vma->vm_private_data; + struct gru_thread_state *gts, *ngts; + + gts = gru_alloc_gts(vma, vdata, tsid); + if (!gts) + return NULL; + + spin_lock(&vdata->vd_lock); + ngts = gru_find_current_gts_nolock(vdata, tsid); + if (ngts) { + gts_drop(gts); + gts = ngts; + STAT(gts_double_allocate); + } else { + list_add(>s->ts_next, &vdata->vd_head); + } + spin_unlock(&vdata->vd_lock); + gru_dbg(grudev, "vma %p, gts %p\n", vma, gts); + return gts; +} + +/* + * Free the GRU context assigned to the thread state. + */ +static void gru_free_gru_context(struct gru_thread_state *gts) +{ + struct gru_state *gru; + + gru = gts->ts_gru; + gru_dbg(grudev, "gts %p, gru %p\n", gts, gru); + + spin_lock(&gru->gs_lock); + gru->gs_gts[gts->ts_ctxnum] = NULL; + free_gru_resources(gru, gts); + BUG_ON(test_bit(gts->ts_ctxnum, &gru->gs_context_map) == 0); + __clear_bit(gts->ts_ctxnum, &gru->gs_context_map); + gts->ts_ctxnum = NULLCTX; + gts->ts_gru = NULL; + spin_unlock(&gru->gs_lock); + + gts_drop(gts); + STAT(free_context); +} + +/* + * Prefetching cachelines help hardware performance. + */ +static void prefetch_data(void *p, int num, int stride) +{ + while (num-- > 0) { + prefetchw(p); + p += stride; + } +} + +static inline long gru_copy_handle(void *d, void *s) +{ + memcpy(d, s, GRU_HANDLE_BYTES); + return GRU_HANDLE_BYTES; +} + +/* rewrite in assembly & use lots of prefetch */ +static void gru_load_context_data(void *save, void *grubase, int ctxnum, + unsigned long cbrmap, unsigned long dsrmap) +{ + void *gseg, *cb, *cbe; + unsigned long length; + int i, scr; + + gseg = grubase + ctxnum * GRU_GSEG_STRIDE; + length = hweight64(dsrmap) * GRU_DSR_AU_BYTES; + prefetch_data(gseg + GRU_DS_BASE, length / GRU_CACHE_LINE_BYTES, + GRU_CACHE_LINE_BYTES); + + cb = gseg + GRU_CB_BASE; + cbe = grubase + GRU_CBE_BASE; + for_each_cbr_in_allocation_map(i, &cbrmap, scr) { + prefetch_data(cb, 1, GRU_CACHE_LINE_BYTES); + prefetch_data(cbe + i * GRU_HANDLE_STRIDE, 1, + GRU_CACHE_LINE_BYTES); + cb += GRU_HANDLE_STRIDE; + } + + cb = gseg + GRU_CB_BASE; + for_each_cbr_in_allocation_map(i, &cbrmap, scr) { + save += gru_copy_handle(cb, save); + save += gru_copy_handle(cbe + i * GRU_HANDLE_STRIDE, save); + cb += GRU_HANDLE_STRIDE; + } + + memcpy(gseg + GRU_DS_BASE, save, length); +} + +static void gru_unload_context_data(void *save, void *grubase, int ctxnum, + unsigned long cbrmap, unsigned long dsrmap) +{ + void *gseg, *cb, *cbe; + unsigned long length; + int i, scr; + + gseg = grubase + ctxnum * GRU_GSEG_STRIDE; + + cb = gseg + GRU_CB_BASE; + cbe = grubase + GRU_CBE_BASE; + for_each_cbr_in_allocation_map(i, &cbrmap, scr) { + save += gru_copy_handle(save, cb); + save += gru_copy_handle(save, cbe + i * GRU_HANDLE_STRIDE); + cb += GRU_HANDLE_STRIDE; + } + length = hweight64(dsrmap) * GRU_DSR_AU_BYTES; + memcpy(save, gseg + GRU_DS_BASE, length); +} + +void gru_unload_context(struct gru_thread_state *gts, int savestate) +{ + struct gru_state *gru = gts->ts_gru; + struct gru_context_configuration_handle *cch; + int ctxnum = gts->ts_ctxnum; + + zap_vma_ptes(gts->ts_vma, UGRUADDR(gts), GRU_GSEG_PAGESIZE); + cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); + + lock_cch_handle(cch); + if (cch_interrupt_sync(cch)) + BUG(); + gru_dbg(grudev, "gts %p\n", gts); + + gru_unload_mm_tracker(gru, gts->ts_gms, gts->ts_ctxnum); + if (savestate) + gru_unload_context_data(gts->ts_gdata, gru->gs_gru_base_vaddr, + ctxnum, gts->ts_cbr_map, + gts->ts_dsr_map); + + if (cch_deallocate(cch)) + BUG(); + gts->ts_force_unload = 0; /* ts_force_unload locked by CCH lock */ + unlock_cch_handle(cch); + + gru_free_gru_context(gts); + STAT(unload_context); +} + +/* + * Load a GRU context by copying it from the thread data structure in memory + * to the GRU. + */ +static void gru_load_context(struct gru_thread_state *gts) +{ + struct gru_state *gru = gts->ts_gru; + struct gru_context_configuration_handle *cch; + int err, asid, ctxnum = gts->ts_ctxnum; + + gru_dbg(grudev, "gts %p\n", gts); + cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); + + lock_cch_handle(cch); + asid = gru_load_mm_tracker(gru, gts->ts_gms, gts->ts_ctxnum); + cch->tfm_fault_bit_enable = + (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL + || gts->ts_user_options == GRU_OPT_MISS_FMM_INTR); + cch->tlb_int_enable = (gts->ts_user_options == GRU_OPT_MISS_FMM_INTR); + if (cch->tlb_int_enable) { + gts->ts_tlb_int_select = gru_cpu_fault_map_id(); + cch->tlb_int_select = gts->ts_tlb_int_select; + } + cch->tfm_done_bit_enable = 0; + err = cch_allocate(cch, asid, gts->ts_cbr_map, gts->ts_dsr_map); + if (err) { + gru_dbg(grudev, + "err %d: cch %p, gts %p, cbr 0x%lx, dsr 0x%lx\n", + err, cch, gts, gts->ts_cbr_map, gts->ts_dsr_map); + BUG(); + } + + gru_load_context_data(gts->ts_gdata, gru->gs_gru_base_vaddr, ctxnum, + gts->ts_cbr_map, gts->ts_dsr_map); + + if (cch_start(cch)) + BUG(); + unlock_cch_handle(cch); + + STAT(load_context); +} + +/* + * Update fields in an active CCH: + * - retarget interrupts on local blade + * - force a delayed context unload by clearing the CCH asids. This + * forces TLB misses for new GRU instructions. The context is unloaded + * when the next TLB miss occurs. + */ +static int gru_update_cch(struct gru_thread_state *gts, int int_select) +{ + struct gru_context_configuration_handle *cch; + struct gru_state *gru = gts->ts_gru; + int i, ctxnum = gts->ts_ctxnum, ret = 0; + + cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); + + lock_cch_handle(cch); + if (cch->state == CCHSTATE_ACTIVE) { + if (gru->gs_gts[gts->ts_ctxnum] != gts) + goto exit; + if (cch_interrupt(cch)) + BUG(); + if (int_select >= 0) { + gts->ts_tlb_int_select = int_select; + cch->tlb_int_select = int_select; + } else { + for (i = 0; i < 8; i++) + cch->asid[i] = 0; + cch->tfm_fault_bit_enable = 0; + cch->tlb_int_enable = 0; + gts->ts_force_unload = 1; + } + if (cch_start(cch)) + BUG(); + ret = 1; + } +exit: + unlock_cch_handle(cch); + return ret; +} + +/* + * Update CCH tlb interrupt select. Required when all the following is true: + * - task's GRU context is loaded into a GRU + * - task is using interrupt notification for TLB faults + * - task has migrated to a different cpu on the same blade where + * it was previously running. + */ +static int gru_retarget_intr(struct gru_thread_state *gts) +{ + if (gts->ts_tlb_int_select < 0 + || gts->ts_tlb_int_select == gru_cpu_fault_map_id()) + return 0; + + gru_dbg(grudev, "retarget from %d to %d\n", gts->ts_tlb_int_select, + gru_cpu_fault_map_id()); + return gru_update_cch(gts, gru_cpu_fault_map_id()); +} + + +/* + * Insufficient GRU resources available on the local blade. Steal a context from + * a process. This is a hack until a _real_ resource scheduler is written.... + */ +#define next_ctxnum(n) ((n) < GRU_NUM_CCH - 2 ? (n) + 1 : 0) +#define next_gru(b, g) (((g) < &(b)->bs_grus[GRU_CHIPLETS_PER_BLADE - 1]) ? \ + ((g)+1) : &(b)->bs_grus[0]) + +static void gru_steal_context(struct gru_thread_state *gts) +{ + struct gru_blade_state *blade; + struct gru_state *gru, *gru0; + struct gru_thread_state *ngts = NULL; + int ctxnum, ctxnum0, flag = 0, cbr, dsr; + + cbr = gts->ts_cbr_au_count; + dsr = gts->ts_dsr_au_count; + + preempt_disable(); + blade = gru_base[uv_numa_blade_id()]; + spin_lock(&blade->bs_lock); + + ctxnum = next_ctxnum(blade->bs_lru_ctxnum); + gru = blade->bs_lru_gru; + if (ctxnum == 0) + gru = next_gru(blade, gru); + ctxnum0 = ctxnum; + gru0 = gru; + while (1) { + if (check_gru_resources(gru, cbr, dsr, GRU_NUM_CCH)) + break; + spin_lock(&gru->gs_lock); + for (; ctxnum < GRU_NUM_CCH; ctxnum++) { + if (flag && gru == gru0 && ctxnum == ctxnum0) + break; + ngts = gru->gs_gts[ctxnum]; + /* + * We are grabbing locks out of order, so trylock is + * needed. GTSs are usually not locked, so the odds of + * success are high. If trylock fails, try to steal a + * different GSEG. + */ + if (ngts && mutex_trylock(&ngts->ts_ctxlock)) + break; + ngts = NULL; + flag = 1; + } + spin_unlock(&gru->gs_lock); + if (ngts || (flag && gru == gru0 && ctxnum == ctxnum0)) + break; + ctxnum = 0; + gru = next_gru(blade, gru); + } + blade->bs_lru_gru = gru; + blade->bs_lru_ctxnum = ctxnum; + spin_unlock(&blade->bs_lock); + preempt_enable(); + + if (ngts) { + STAT(steal_context); + ngts->ts_steal_jiffies = jiffies; + gru_unload_context(ngts, 1); + mutex_unlock(&ngts->ts_ctxlock); + } else { + STAT(steal_context_failed); + } + gru_dbg(grudev, + "stole gru %x, ctxnum %d from gts %p. Need cb %d, ds %d;" + " avail cb %ld, ds %ld\n", + gru->gs_gid, ctxnum, ngts, cbr, dsr, hweight64(gru->gs_cbr_map), + hweight64(gru->gs_dsr_map)); +} + +/* + * Scan the GRUs on the local blade & assign a GRU context. + */ +static struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts) +{ + struct gru_state *gru, *grux; + int i, max_active_contexts; + + preempt_disable(); + +again: + gru = NULL; + max_active_contexts = GRU_NUM_CCH; + for_each_gru_on_blade(grux, uv_numa_blade_id(), i) { + if (check_gru_resources(grux, gts->ts_cbr_au_count, + gts->ts_dsr_au_count, + max_active_contexts)) { + gru = grux; + max_active_contexts = grux->gs_active_contexts; + if (max_active_contexts == 0) + break; + } + } + + if (gru) { + spin_lock(&gru->gs_lock); + if (!check_gru_resources(gru, gts->ts_cbr_au_count, + gts->ts_dsr_au_count, GRU_NUM_CCH)) { + spin_unlock(&gru->gs_lock); + goto again; + } + reserve_gru_resources(gru, gts); + gts->ts_gru = gru; + gts->ts_ctxnum = + find_first_zero_bit(&gru->gs_context_map, GRU_NUM_CCH); + BUG_ON(gts->ts_ctxnum == GRU_NUM_CCH); + atomic_inc(>s->ts_refcnt); + gru->gs_gts[gts->ts_ctxnum] = gts; + __set_bit(gts->ts_ctxnum, &gru->gs_context_map); + spin_unlock(&gru->gs_lock); + + STAT(assign_context); + gru_dbg(grudev, + "gseg %p, gts %p, gru %x, ctx %d, cbr %d, dsr %d\n", + gseg_virtual_address(gts->ts_gru, gts->ts_ctxnum), gts, + gts->ts_gru->gs_gid, gts->ts_ctxnum, + gts->ts_cbr_au_count, gts->ts_dsr_au_count); + } else { + gru_dbg(grudev, "failed to allocate a GTS %s\n", ""); + STAT(assign_context_failed); + } + + preempt_enable(); + return gru; +} + +/* + * gru_nopage + * + * Map the user's GRU segment + */ +int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct gru_thread_state *gts; + unsigned long paddr, vaddr; + + vaddr = (unsigned long)vmf->virtual_address; + gru_dbg(grudev, "vma %p, vaddr 0x%lx (0x%lx)\n", + vma, vaddr, GSEG_BASE(vaddr)); + STAT(nopfn); + + gts = gru_find_thread_state(vma, TSID(vaddr, vma)); + if (!gts) + return VM_FAULT_SIGBUS; + +again: + preempt_disable(); + mutex_lock(>s->ts_ctxlock); + if (gts->ts_gru) { + if (gts->ts_gru->gs_blade_id != uv_numa_blade_id()) { + STAT(migrated_nopfn_unload); + gru_unload_context(gts, 1); + } else { + if (gru_retarget_intr(gts)) + STAT(migrated_nopfn_retarget); + } + } + + if (!gts->ts_gru) { + while (!gru_assign_gru_context(gts)) { + mutex_unlock(>s->ts_ctxlock); + preempt_enable(); + schedule_timeout(GRU_ASSIGN_DELAY); /* true hack ZZZ */ + if (gts->ts_steal_jiffies + GRU_STEAL_DELAY < jiffies) + gru_steal_context(gts); + goto again; + } + gru_load_context(gts); + paddr = gseg_physical_address(gts->ts_gru, gts->ts_ctxnum); + remap_pfn_range(vma, vaddr & ~(GRU_GSEG_PAGESIZE - 1), + paddr >> PAGE_SHIFT, GRU_GSEG_PAGESIZE, + vma->vm_page_prot); + } + + mutex_unlock(>s->ts_ctxlock); + preempt_enable(); + + return VM_FAULT_NOPAGE; +} + -- cgit v1.2.3 From 1d09d737ab017ff7a9745962e19909713ac89b37 Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Tue, 29 Jul 2008 22:33:59 -0700 Subject: GRU Driver: /proc interfaces This file externalizes some GRU state & statistics to the user using the /proc file system. Signed-off-by: Jack Steiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-gru/gruprocfs.c | 336 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 336 insertions(+) create mode 100644 drivers/misc/sgi-gru/gruprocfs.c (limited to 'drivers') diff --git a/drivers/misc/sgi-gru/gruprocfs.c b/drivers/misc/sgi-gru/gruprocfs.c new file mode 100644 index 00000000000..bdb1ad83bbf --- /dev/null +++ b/drivers/misc/sgi-gru/gruprocfs.c @@ -0,0 +1,336 @@ +/* + * SN Platform GRU Driver + * + * PROC INTERFACES + * + * This file supports the /proc interfaces for the GRU driver + * + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include "gru.h" +#include "grulib.h" +#include "grutables.h" + +#define printstat(s, f) printstat_val(s, &gru_stats.f, #f) + +static void printstat_val(struct seq_file *s, atomic_long_t *v, char *id) +{ + unsigned long val = atomic_long_read(v); + + if (val) + seq_printf(s, "%16lu %s\n", val, id); +} + +static int statistics_show(struct seq_file *s, void *p) +{ + printstat(s, vdata_alloc); + printstat(s, vdata_free); + printstat(s, gts_alloc); + printstat(s, gts_free); + printstat(s, vdata_double_alloc); + printstat(s, gts_double_allocate); + printstat(s, assign_context); + printstat(s, assign_context_failed); + printstat(s, free_context); + printstat(s, load_context); + printstat(s, unload_context); + printstat(s, steal_context); + printstat(s, steal_context_failed); + printstat(s, nopfn); + printstat(s, break_cow); + printstat(s, asid_new); + printstat(s, asid_next); + printstat(s, asid_wrap); + printstat(s, asid_reuse); + printstat(s, intr); + printstat(s, call_os); + printstat(s, call_os_check_for_bug); + printstat(s, call_os_wait_queue); + printstat(s, user_flush_tlb); + printstat(s, user_unload_context); + printstat(s, user_exception); + printstat(s, set_task_slice); + printstat(s, migrate_check); + printstat(s, migrated_retarget); + printstat(s, migrated_unload); + printstat(s, migrated_unload_delay); + printstat(s, migrated_nopfn_retarget); + printstat(s, migrated_nopfn_unload); + printstat(s, tlb_dropin); + printstat(s, tlb_dropin_fail_no_asid); + printstat(s, tlb_dropin_fail_upm); + printstat(s, tlb_dropin_fail_invalid); + printstat(s, tlb_dropin_fail_range_active); + printstat(s, tlb_dropin_fail_idle); + printstat(s, tlb_dropin_fail_fmm); + printstat(s, mmu_invalidate_range); + printstat(s, mmu_invalidate_page); + printstat(s, mmu_clear_flush_young); + printstat(s, flush_tlb); + printstat(s, flush_tlb_gru); + printstat(s, flush_tlb_gru_tgh); + printstat(s, flush_tlb_gru_zero_asid); + printstat(s, copy_gpa); + printstat(s, mesq_receive); + printstat(s, mesq_receive_none); + printstat(s, mesq_send); + printstat(s, mesq_send_failed); + printstat(s, mesq_noop); + printstat(s, mesq_send_unexpected_error); + printstat(s, mesq_send_lb_overflow); + printstat(s, mesq_send_qlimit_reached); + printstat(s, mesq_send_amo_nacked); + printstat(s, mesq_send_put_nacked); + printstat(s, mesq_qf_not_full); + printstat(s, mesq_qf_locked); + printstat(s, mesq_qf_noop_not_full); + printstat(s, mesq_qf_switch_head_failed); + printstat(s, mesq_qf_unexpected_error); + printstat(s, mesq_noop_unexpected_error); + printstat(s, mesq_noop_lb_overflow); + printstat(s, mesq_noop_qlimit_reached); + printstat(s, mesq_noop_amo_nacked); + printstat(s, mesq_noop_put_nacked); + return 0; +} + +static ssize_t statistics_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *data) +{ + memset(&gru_stats, 0, sizeof(gru_stats)); + return count; +} + +static int options_show(struct seq_file *s, void *p) +{ + seq_printf(s, "0x%lx\n", options); + return 0; +} + +static ssize_t options_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *data) +{ + unsigned long val; + char buf[80]; + + if (copy_from_user + (buf, userbuf, count < sizeof(buf) ? count : sizeof(buf))) + return -EFAULT; + if (!strict_strtoul(buf, 10, &val)) + options = val; + + return count; +} + +static int cch_seq_show(struct seq_file *file, void *data) +{ + long gid = *(long *)data; + int i; + struct gru_state *gru = GID_TO_GRU(gid); + struct gru_thread_state *ts; + const char *mode[] = { "??", "UPM", "INTR", "OS_POLL" }; + + if (gid == 0) + seq_printf(file, "#%5s%5s%6s%9s%6s%8s%8s\n", "gid", "bid", + "ctx#", "pid", "cbrs", "dsbytes", "mode"); + if (gru) + for (i = 0; i < GRU_NUM_CCH; i++) { + ts = gru->gs_gts[i]; + if (!ts) + continue; + seq_printf(file, " %5d%5d%6d%9d%6d%8d%8s\n", + gru->gs_gid, gru->gs_blade_id, i, + ts->ts_tgid_owner, + ts->ts_cbr_au_count * GRU_CBR_AU_SIZE, + ts->ts_cbr_au_count * GRU_DSR_AU_BYTES, + mode[ts->ts_user_options & + GRU_OPT_MISS_MASK]); + } + + return 0; +} + +static int gru_seq_show(struct seq_file *file, void *data) +{ + long gid = *(long *)data, ctxfree, cbrfree, dsrfree; + struct gru_state *gru = GID_TO_GRU(gid); + + if (gid == 0) { + seq_printf(file, "#%5s%5s%7s%6s%6s%8s%6s%6s\n", "gid", "nid", + "ctx", "cbr", "dsr", "ctx", "cbr", "dsr"); + seq_printf(file, "#%5s%5s%7s%6s%6s%8s%6s%6s\n", "", "", "busy", + "busy", "busy", "free", "free", "free"); + } + if (gru) { + ctxfree = GRU_NUM_CCH - gru->gs_active_contexts; + cbrfree = hweight64(gru->gs_cbr_map) * GRU_CBR_AU_SIZE; + dsrfree = hweight64(gru->gs_dsr_map) * GRU_DSR_AU_BYTES; + seq_printf(file, " %5d%5d%7ld%6ld%6ld%8ld%6ld%6ld\n", + gru->gs_gid, gru->gs_blade_id, GRU_NUM_CCH - ctxfree, + GRU_NUM_CBE - cbrfree, GRU_NUM_DSR_BYTES - dsrfree, + ctxfree, cbrfree, dsrfree); + } + + return 0; +} + +static void seq_stop(struct seq_file *file, void *data) +{ +} + +static void *seq_start(struct seq_file *file, loff_t *gid) +{ + if (*gid < GRU_MAX_GRUS) + return gid; + return NULL; +} + +static void *seq_next(struct seq_file *file, void *data, loff_t *gid) +{ + (*gid)++; + if (*gid < GRU_MAX_GRUS) + return gid; + return NULL; +} + +static const struct seq_operations cch_seq_ops = { + .start = seq_start, + .next = seq_next, + .stop = seq_stop, + .show = cch_seq_show +}; + +static const struct seq_operations gru_seq_ops = { + .start = seq_start, + .next = seq_next, + .stop = seq_stop, + .show = gru_seq_show +}; + +static int statistics_open(struct inode *inode, struct file *file) +{ + return single_open(file, statistics_show, NULL); +} + +static int options_open(struct inode *inode, struct file *file) +{ + return single_open(file, options_show, NULL); +} + +static int cch_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &cch_seq_ops); +} + +static int gru_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &gru_seq_ops); +} + +/* *INDENT-OFF* */ +static const struct file_operations statistics_fops = { + .open = statistics_open, + .read = seq_read, + .write = statistics_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations options_fops = { + .open = options_open, + .read = seq_read, + .write = options_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations cch_fops = { + .open = cch_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; +static const struct file_operations gru_fops = { + .open = gru_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static struct proc_entry { + char *name; + int mode; + const struct file_operations *fops; + struct proc_dir_entry *entry; +} proc_files[] = { + {"statistics", 0644, &statistics_fops}, + {"debug_options", 0644, &options_fops}, + {"cch_status", 0444, &cch_fops}, + {"gru_status", 0444, &gru_fops}, + {NULL} +}; +/* *INDENT-ON* */ + +static struct proc_dir_entry *proc_gru __read_mostly; + +static int create_proc_file(struct proc_entry *p) +{ + p->entry = create_proc_entry(p->name, p->mode, proc_gru); + if (!p->entry) + return -1; + p->entry->proc_fops = p->fops; + return 0; +} + +static void delete_proc_files(void) +{ + struct proc_entry *p; + + if (proc_gru) { + for (p = proc_files; p->name; p++) + if (p->entry) + remove_proc_entry(p->name, proc_gru); + remove_proc_entry("gru", NULL); + } +} + +int gru_proc_init(void) +{ + struct proc_entry *p; + + proc_mkdir("sgi_uv", NULL); + proc_gru = proc_mkdir("sgi_uv/gru", NULL); + + for (p = proc_files; p->name; p++) + if (create_proc_file(p)) + goto err; + return 0; + +err: + delete_proc_files(); + return -1; +} + +void gru_proc_exit(void) +{ + delete_proc_files(); +} -- cgit v1.2.3 From ee5b8feca3af01400e26637209a72fbf137c82ff Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Tue, 29 Jul 2008 22:33:59 -0700 Subject: GRU Driver: TLB flushing, MMUOPS callouts This file contains the functions for handlinf GRU TLB flushing, This includes functions to handle the MMUOPS callouts. Signed-off-by: Jack Steiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-gru/grutlbpurge.c | 370 +++++++++++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 drivers/misc/sgi-gru/grutlbpurge.c (limited to 'drivers') diff --git a/drivers/misc/sgi-gru/grutlbpurge.c b/drivers/misc/sgi-gru/grutlbpurge.c new file mode 100644 index 00000000000..bb6b0e64e10 --- /dev/null +++ b/drivers/misc/sgi-gru/grutlbpurge.c @@ -0,0 +1,370 @@ +/* + * SN Platform GRU Driver + * + * MMUOPS callbacks + TLB flushing + * + * This file handles emu notifier callbacks from the core kernel. The callbacks + * are used to update the TLB in the GRU as a result of changes in the + * state of a process address space. This file also handles TLB invalidates + * from the GRU driver. + * + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gru.h" +#include "grutables.h" +#include + +#define gru_random() get_cycles() + +/* ---------------------------------- TLB Invalidation functions -------- + * get_tgh_handle + * + * Find a TGH to use for issuing a TLB invalidate. For GRUs that are on the + * local blade, use a fixed TGH that is a function of the blade-local cpu + * number. Normally, this TGH is private to the cpu & no contention occurs for + * the TGH. For offblade GRUs, select a random TGH in the range above the + * private TGHs. A spinlock is required to access this TGH & the lock must be + * released when the invalidate is completes. This sucks, but it is the best we + * can do. + * + * Note that the spinlock is IN the TGH handle so locking does not involve + * additional cache lines. + * + */ +static inline int get_off_blade_tgh(struct gru_state *gru) +{ + int n; + + n = GRU_NUM_TGH - gru->gs_tgh_first_remote; + n = gru_random() % n; + n += gru->gs_tgh_first_remote; + return n; +} + +static inline int get_on_blade_tgh(struct gru_state *gru) +{ + return uv_blade_processor_id() >> gru->gs_tgh_local_shift; +} + +static struct gru_tlb_global_handle *get_lock_tgh_handle(struct gru_state + *gru) +{ + struct gru_tlb_global_handle *tgh; + int n; + + preempt_disable(); + if (uv_numa_blade_id() == gru->gs_blade_id) + n = get_on_blade_tgh(gru); + else + n = get_off_blade_tgh(gru); + tgh = get_tgh_by_index(gru, n); + lock_tgh_handle(tgh); + + return tgh; +} + +static void get_unlock_tgh_handle(struct gru_tlb_global_handle *tgh) +{ + unlock_tgh_handle(tgh); + preempt_enable(); +} + +/* + * gru_flush_tlb_range + * + * General purpose TLB invalidation function. This function scans every GRU in + * the ENTIRE system (partition) looking for GRUs where the specified MM has + * been accessed by the GRU. For each GRU found, the TLB must be invalidated OR + * the ASID invalidated. Invalidating an ASID causes a new ASID to be assigned + * on the next fault. This effectively flushes the ENTIRE TLB for the MM at the + * cost of (possibly) a large number of future TLBmisses. + * + * The current algorithm is optimized based on the following (somewhat true) + * assumptions: + * - GRU contexts are not loaded into a GRU unless a reference is made to + * the data segment or control block (this is true, not an assumption). + * If a DS/CB is referenced, the user will also issue instructions that + * cause TLBmisses. It is not necessary to optimize for the case where + * contexts are loaded but no instructions cause TLB misses. (I know + * this will happen but I'm not optimizing for it). + * - GRU instructions to invalidate TLB entries are SLOOOOWWW - normally + * a few usec but in unusual cases, it could be longer. Avoid if + * possible. + * - intrablade process migration between cpus is not frequent but is + * common. + * - a GRU context is not typically migrated to a different GRU on the + * blade because of intrablade migration + * - interblade migration is rare. Processes migrate their GRU context to + * the new blade. + * - if interblade migration occurs, migration back to the original blade + * is very very rare (ie., no optimization for this case) + * - most GRU instruction operate on a subset of the user REGIONS. Code + * & shared library regions are not likely targets of GRU instructions. + * + * To help improve the efficiency of TLB invalidation, the GMS data + * structure is maintained for EACH address space (MM struct). The GMS is + * also the structure that contains the pointer to the mmu callout + * functions. This structure is linked to the mm_struct for the address space + * using the mmu "register" function. The mmu interfaces are used to + * provide the callbacks for TLB invalidation. The GMS contains: + * + * - asid[maxgrus] array. ASIDs are assigned to a GRU when a context is + * loaded into the GRU. + * - asidmap[maxgrus]. bitmap to make it easier to find non-zero asids in + * the above array + * - ctxbitmap[maxgrus]. Indicates the contexts that are currently active + * in the GRU for the address space. This bitmap must be passed to the + * GRU to do an invalidate. + * + * The current algorithm for invalidating TLBs is: + * - scan the asidmap for GRUs where the context has been loaded, ie, + * asid is non-zero. + * - for each gru found: + * - if the ctxtmap is non-zero, there are active contexts in the + * GRU. TLB invalidate instructions must be issued to the GRU. + * - if the ctxtmap is zero, no context is active. Set the ASID to + * zero to force a full TLB invalidation. This is fast but will + * cause a lot of TLB misses if the context is reloaded onto the + * GRU + * + */ + +void gru_flush_tlb_range(struct gru_mm_struct *gms, unsigned long start, + unsigned long len) +{ + struct gru_state *gru; + struct gru_mm_tracker *asids; + struct gru_tlb_global_handle *tgh; + unsigned long num; + int grupagesize, pagesize, pageshift, gid, asid; + + /* ZZZ TODO - handle huge pages */ + pageshift = PAGE_SHIFT; + pagesize = (1UL << pageshift); + grupagesize = GRU_PAGESIZE(pageshift); + num = min(((len + pagesize - 1) >> pageshift), GRUMAXINVAL); + + STAT(flush_tlb); + gru_dbg(grudev, "gms %p, start 0x%lx, len 0x%lx, asidmap 0x%lx\n", gms, + start, len, gms->ms_asidmap[0]); + + spin_lock(&gms->ms_asid_lock); + for_each_gru_in_bitmap(gid, gms->ms_asidmap) { + STAT(flush_tlb_gru); + gru = GID_TO_GRU(gid); + asids = gms->ms_asids + gid; + asid = asids->mt_asid; + if (asids->mt_ctxbitmap && asid) { + STAT(flush_tlb_gru_tgh); + asid = GRUASID(asid, start); + gru_dbg(grudev, + " FLUSH gruid %d, asid 0x%x, num %ld, cbmap 0x%x\n", + gid, asid, num, asids->mt_ctxbitmap); + tgh = get_lock_tgh_handle(gru); + tgh_invalidate(tgh, start, 0, asid, grupagesize, 0, + num - 1, asids->mt_ctxbitmap); + get_unlock_tgh_handle(tgh); + } else { + STAT(flush_tlb_gru_zero_asid); + asids->mt_asid = 0; + __clear_bit(gru->gs_gid, gms->ms_asidmap); + gru_dbg(grudev, + " CLEARASID gruid %d, asid 0x%x, cbtmap 0x%x, asidmap 0x%lx\n", + gid, asid, asids->mt_ctxbitmap, + gms->ms_asidmap[0]); + } + } + spin_unlock(&gms->ms_asid_lock); +} + +/* + * Flush the entire TLB on a chiplet. + */ +void gru_flush_all_tlb(struct gru_state *gru) +{ + struct gru_tlb_global_handle *tgh; + + gru_dbg(grudev, "gru %p, gid %d\n", gru, gru->gs_gid); + tgh = get_lock_tgh_handle(gru); + tgh_invalidate(tgh, 0, ~0, 0, 1, 1, GRUMAXINVAL - 1, 0); + get_unlock_tgh_handle(tgh); + preempt_enable(); +} + +/* + * MMUOPS notifier callout functions + */ +static void gru_invalidate_range_start(struct mmu_notifier *mn, + struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct, + ms_notifier); + + STAT(mmu_invalidate_range); + atomic_inc(&gms->ms_range_active); + gru_dbg(grudev, "gms %p, start 0x%lx, end 0x%lx, act %d\n", gms, + start, end, atomic_read(&gms->ms_range_active)); + gru_flush_tlb_range(gms, start, end - start); +} + +static void gru_invalidate_range_end(struct mmu_notifier *mn, + struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct, + ms_notifier); + + atomic_dec(&gms->ms_range_active); + wake_up_all(&gms->ms_wait_queue); + gru_dbg(grudev, "gms %p, start 0x%lx, end 0x%lx\n", gms, start, end); +} + +static void gru_invalidate_page(struct mmu_notifier *mn, struct mm_struct *mm, + unsigned long address) +{ + struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct, + ms_notifier); + + STAT(mmu_invalidate_page); + gru_flush_tlb_range(gms, address, PAGE_SIZE); + gru_dbg(grudev, "gms %p, address 0x%lx\n", gms, address); +} + +static void gru_release(struct mmu_notifier *mn, struct mm_struct *mm) +{ + struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct, + ms_notifier); + + gms->ms_released = 1; + gru_dbg(grudev, "gms %p\n", gms); +} + + +static const struct mmu_notifier_ops gru_mmuops = { + .invalidate_page = gru_invalidate_page, + .invalidate_range_start = gru_invalidate_range_start, + .invalidate_range_end = gru_invalidate_range_end, + .release = gru_release, +}; + +/* Move this to the basic mmu_notifier file. But for now... */ +static struct mmu_notifier *mmu_find_ops(struct mm_struct *mm, + const struct mmu_notifier_ops *ops) +{ + struct mmu_notifier *mn, *gru_mn = NULL; + struct hlist_node *n; + + if (mm->mmu_notifier_mm) { + rcu_read_lock(); + hlist_for_each_entry_rcu(mn, n, &mm->mmu_notifier_mm->list, + hlist) + if (mn->ops == ops) { + gru_mn = mn; + break; + } + rcu_read_unlock(); + } + return gru_mn; +} + +struct gru_mm_struct *gru_register_mmu_notifier(void) +{ + struct gru_mm_struct *gms; + struct mmu_notifier *mn; + + mn = mmu_find_ops(current->mm, &gru_mmuops); + if (mn) { + gms = container_of(mn, struct gru_mm_struct, ms_notifier); + atomic_inc(&gms->ms_refcnt); + } else { + gms = kzalloc(sizeof(*gms), GFP_KERNEL); + if (gms) { + spin_lock_init(&gms->ms_asid_lock); + gms->ms_notifier.ops = &gru_mmuops; + atomic_set(&gms->ms_refcnt, 1); + init_waitqueue_head(&gms->ms_wait_queue); + __mmu_notifier_register(&gms->ms_notifier, current->mm); + } + } + gru_dbg(grudev, "gms %p, refcnt %d\n", gms, + atomic_read(&gms->ms_refcnt)); + return gms; +} + +void gru_drop_mmu_notifier(struct gru_mm_struct *gms) +{ + gru_dbg(grudev, "gms %p, refcnt %d, released %d\n", gms, + atomic_read(&gms->ms_refcnt), gms->ms_released); + if (atomic_dec_return(&gms->ms_refcnt) == 0) { + if (!gms->ms_released) + mmu_notifier_unregister(&gms->ms_notifier, current->mm); + kfree(gms); + } +} + +/* + * Setup TGH parameters. There are: + * - 24 TGH handles per GRU chiplet + * - a portion (MAX_LOCAL_TGH) of the handles are reserved for + * use by blade-local cpus + * - the rest are used by off-blade cpus. This usage is + * less frequent than blade-local usage. + * + * For now, use 16 handles for local flushes, 8 for remote flushes. If the blade + * has less tan or equal to 16 cpus, each cpu has a unique handle that it can + * use. + */ +#define MAX_LOCAL_TGH 16 + +void gru_tgh_flush_init(struct gru_state *gru) +{ + int cpus, shift = 0, n; + + cpus = uv_blade_nr_possible_cpus(gru->gs_blade_id); + + /* n = cpus rounded up to next power of 2 */ + if (cpus) { + n = 1 << fls(cpus - 1); + + /* + * shift count for converting local cpu# to TGH index + * 0 if cpus <= MAX_LOCAL_TGH, + * 1 if cpus <= 2*MAX_LOCAL_TGH, + * etc + */ + shift = max(0, fls(n - 1) - fls(MAX_LOCAL_TGH - 1)); + } + gru->gs_tgh_local_shift = shift; + + /* first starting TGH index to use for remote purges */ + gru->gs_tgh_first_remote = (cpus + (1 << shift) - 1) >> shift; + +} -- cgit v1.2.3 From 3c45f6928322773b1810fbec1ece77056f914114 Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Tue, 29 Jul 2008 22:34:00 -0700 Subject: GRU Driver: driver makefile This patch adds the GRU driver makefile Signed-off-by: Jack Steiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-gru/Makefile | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 drivers/misc/sgi-gru/Makefile (limited to 'drivers') diff --git a/drivers/misc/sgi-gru/Makefile b/drivers/misc/sgi-gru/Makefile new file mode 100644 index 00000000000..d03597a521b --- /dev/null +++ b/drivers/misc/sgi-gru/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_SGI_GRU) := gru.o +gru-y := grufile.o grumain.o grufault.o grutlbpurge.o gruprocfs.o grukservices.o + -- cgit v1.2.3 From 3d919e5f6b440bb0cc7996eb7628b29be09e6343 Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Tue, 29 Jul 2008 22:34:01 -0700 Subject: GRU Driver: driver/misc Makefile & Kconfig changes Driver/misc changes for the GRU driver Signed-off-by: Jack Steiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/Kconfig | 23 +++++++++++++++++++++++ drivers/misc/Makefile | 1 + 2 files changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index f5ade1904aa..4b288f43ca8 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -450,4 +450,27 @@ config HP_ILO To compile this driver as a module, choose M here: the module will be called hpilo. +config SGI_GRU + tristate "SGI GRU driver" + depends on (X86_64 || IA64_SGI_UV || IA64_GENERIC) && SMP + default n + select MMU_NOTIFIER + ---help--- + The GRU is a hardware resource located in the system chipset. The GRU + contains memory that can be mmapped into the user address space. This memory is + used to communicate with the GRU to perform functions such as load/store, + scatter/gather, bcopy, AMOs, etc. The GRU is directly accessed by user + instructions using user virtual addresses. GRU instructions (ex., bcopy) use + user virtual addresses for operands. + + If you are not running on a SGI UV system, say N. + +config SGI_GRU_DEBUG + bool "SGI GRU driver debug" + depends on SGI_GRU + default n + ---help--- + This option enables addition debugging code for the SGI GRU driver. If + you are unsure, say N. + endif # MISC_DEVICES diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index f5e273420c0..c6c13f60b45 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -28,4 +28,5 @@ obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o obj-$(CONFIG_KGDB_TESTS) += kgdbts.o obj-$(CONFIG_SGI_XP) += sgi-xp/ +obj-$(CONFIG_SGI_GRU) += sgi-gru/ obj-$(CONFIG_HP_ILO) += hpilo.o -- cgit v1.2.3 From 9ca8e40c130c906c1060d105e63628410c860261 Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Tue, 29 Jul 2008 22:34:02 -0700 Subject: GRU Driver V3: fixes to resolve code review comments Fixes problems identified in a code review: - add comment with high level dscription of the GRU - prepend "gru_" to all global names - delete unused function - couple of trivial bug fixes [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Jack Steiner Cc: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-gru/gru_instructions.h | 10 ----- drivers/misc/sgi-gru/grufile.c | 8 +++- drivers/misc/sgi-gru/grukservices.c | 6 +-- drivers/misc/sgi-gru/grumain.c | 16 ++++--- drivers/misc/sgi-gru/gruprocfs.c | 4 +- drivers/misc/sgi-gru/grutables.h | 74 ++++++++++++++++++++++++++++++--- drivers/misc/sgi-gru/grutlbpurge.c | 4 +- 7 files changed, 93 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-gru/gru_instructions.h b/drivers/misc/sgi-gru/gru_instructions.h index 3159b261c5a..0dc36225c7c 100644 --- a/drivers/misc/sgi-gru/gru_instructions.h +++ b/drivers/misc/sgi-gru/gru_instructions.h @@ -284,16 +284,6 @@ __opword(unsigned char opcode, unsigned char exopc, unsigned char xtype, (exopc << GRU_CB_EXOPC_SHFT); } -/* - * Prefetch a cacheline. Fetch is unconditional. Must page fault if - * no valid TLB entry is found. - * ??? should I use actual "load" or hardware prefetch??? - */ -static inline void gru_prefetch(void *p) -{ - *(volatile char *)p; -} - /* * Architecture specific intrinsics */ diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c index 09c9c65ff9d..23c91f5f6b6 100644 --- a/drivers/misc/sgi-gru/grufile.c +++ b/drivers/misc/sgi-gru/grufile.c @@ -112,6 +112,10 @@ static int gru_file_mmap(struct file *file, struct vm_area_struct *vma) if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) != (VM_SHARED | VM_WRITE)) return -EPERM; + if (vma->vm_start & (GRU_GSEG_PAGESIZE - 1) || + vma->vm_end & (GRU_GSEG_PAGESIZE - 1)) + return -EINVAL; + vma->vm_flags |= (VM_IO | VM_DONTCOPY | VM_LOCKED | VM_DONTEXPAND | VM_PFNMAP | VM_RESERVED); @@ -471,8 +475,8 @@ struct vm_operations_struct gru_vm_ops = { module_init(gru_init); module_exit(gru_exit); -module_param(options, ulong, 0644); -MODULE_PARM_DESC(options, "Various debug options"); +module_param(gru_options, ulong, 0644); +MODULE_PARM_DESC(gru_options, "Various debug options"); MODULE_AUTHOR("Silicon Graphics, Inc."); MODULE_LICENSE("GPL"); diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c index 234d165fb11..dfd49af0fe1 100644 --- a/drivers/misc/sgi-gru/grukservices.c +++ b/drivers/misc/sgi-gru/grukservices.c @@ -638,11 +638,11 @@ int gru_kservices_init(struct gru_state *gru) cpus_possible = uv_blade_nr_possible_cpus(gru->gs_blade_id); num = GRU_NUM_KERNEL_CBR * cpus_possible; - cbr_map = reserve_gru_cb_resources(gru, GRU_CB_COUNT_TO_AU(num), NULL); + cbr_map = gru_reserve_cb_resources(gru, GRU_CB_COUNT_TO_AU(num), NULL); gru->gs_reserved_cbrs += num; num = GRU_NUM_KERNEL_DSR_BYTES * cpus_possible; - dsr_map = reserve_gru_ds_resources(gru, GRU_DS_BYTES_TO_AU(num), NULL); + dsr_map = gru_reserve_ds_resources(gru, GRU_DS_BYTES_TO_AU(num), NULL); gru->gs_reserved_dsr_bytes += num; gru->gs_active_contexts++; @@ -673,7 +673,7 @@ int gru_kservices_init(struct gru_state *gru) } unlock_cch_handle(cch); - if (options & GRU_QUICKLOOK) + if (gru_options & GRU_QUICKLOOK) quicktest(gru); return 0; } diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c index aef6822cb80..0eeb8dddd2f 100644 --- a/drivers/misc/sgi-gru/grumain.c +++ b/drivers/misc/sgi-gru/grumain.c @@ -22,7 +22,7 @@ #include "grutables.h" #include "gruhandles.h" -unsigned long options __read_mostly; +unsigned long gru_options __read_mostly; static struct device_driver gru_driver = { .name = "gru" @@ -163,14 +163,14 @@ static unsigned long reserve_resources(unsigned long *p, int n, int mmax, return bits; } -unsigned long reserve_gru_cb_resources(struct gru_state *gru, int cbr_au_count, +unsigned long gru_reserve_cb_resources(struct gru_state *gru, int cbr_au_count, char *cbmap) { return reserve_resources(&gru->gs_cbr_map, cbr_au_count, GRU_CBR_AU, cbmap); } -unsigned long reserve_gru_ds_resources(struct gru_state *gru, int dsr_au_count, +unsigned long gru_reserve_ds_resources(struct gru_state *gru, int dsr_au_count, char *dsmap) { return reserve_resources(&gru->gs_dsr_map, dsr_au_count, GRU_DSR_AU, @@ -182,10 +182,10 @@ static void reserve_gru_resources(struct gru_state *gru, { gru->gs_active_contexts++; gts->ts_cbr_map = - reserve_gru_cb_resources(gru, gts->ts_cbr_au_count, + gru_reserve_cb_resources(gru, gts->ts_cbr_au_count, gts->ts_cbr_idx); gts->ts_dsr_map = - reserve_gru_ds_resources(gru, gts->ts_dsr_au_count, NULL); + gru_reserve_ds_resources(gru, gts->ts_dsr_au_count, NULL); } static void free_gru_resources(struct gru_state *gru, @@ -416,6 +416,7 @@ static void gru_free_gru_context(struct gru_thread_state *gts) /* * Prefetching cachelines help hardware performance. + * (Strictly a performance enhancement. Not functionally required). */ static void prefetch_data(void *p, int num, int stride) { @@ -746,6 +747,8 @@ again: * gru_nopage * * Map the user's GRU segment + * + * Note: gru segments alway mmaped on GRU_GSEG_PAGESIZE boundaries. */ int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { @@ -757,6 +760,7 @@ int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf) vma, vaddr, GSEG_BASE(vaddr)); STAT(nopfn); + /* The following check ensures vaddr is a valid address in the VMA */ gts = gru_find_thread_state(vma, TSID(vaddr, vma)); if (!gts) return VM_FAULT_SIGBUS; @@ -775,7 +779,7 @@ again: } if (!gts->ts_gru) { - while (!gru_assign_gru_context(gts)) { + if (!gru_assign_gru_context(gts)) { mutex_unlock(>s->ts_ctxlock); preempt_enable(); schedule_timeout(GRU_ASSIGN_DELAY); /* true hack ZZZ */ diff --git a/drivers/misc/sgi-gru/gruprocfs.c b/drivers/misc/sgi-gru/gruprocfs.c index bdb1ad83bbf..533923f83f1 100644 --- a/drivers/misc/sgi-gru/gruprocfs.c +++ b/drivers/misc/sgi-gru/gruprocfs.c @@ -122,7 +122,7 @@ static ssize_t statistics_write(struct file *file, const char __user *userbuf, static int options_show(struct seq_file *s, void *p) { - seq_printf(s, "0x%lx\n", options); + seq_printf(s, "0x%lx\n", gru_options); return 0; } @@ -136,7 +136,7 @@ static ssize_t options_write(struct file *file, const char __user *userbuf, (buf, userbuf, count < sizeof(buf) ? count : sizeof(buf))) return -EFAULT; if (!strict_strtoul(buf, 10, &val)) - options = val; + gru_options = val; return count; } diff --git a/drivers/misc/sgi-gru/grutables.h b/drivers/misc/sgi-gru/grutables.h index f97d8464012..4251018f70f 100644 --- a/drivers/misc/sgi-gru/grutables.h +++ b/drivers/misc/sgi-gru/grutables.h @@ -24,6 +24,70 @@ #define __GRUTABLES_H__ /* + * GRU Chiplet: + * The GRU is a user addressible memory accelerator. It provides + * several forms of load, store, memset, bcopy instructions. In addition, it + * contains special instructions for AMOs, sending messages to message + * queues, etc. + * + * The GRU is an integral part of the node controller. It connects + * directly to the cpu socket. In its current implementation, there are 2 + * GRU chiplets in the node controller on each blade (~node). + * + * The entire GRU memory space is fully coherent and cacheable by the cpus. + * + * Each GRU chiplet has a physical memory map that looks like the following: + * + * +-----------------+ + * |/////////////////| + * |/////////////////| + * |/////////////////| + * |/////////////////| + * |/////////////////| + * |/////////////////| + * |/////////////////| + * |/////////////////| + * +-----------------+ + * | system control | + * +-----------------+ _______ +-------------+ + * |/////////////////| / | | + * |/////////////////| / | | + * |/////////////////| / | instructions| + * |/////////////////| / | | + * |/////////////////| / | | + * |/////////////////| / |-------------| + * |/////////////////| / | | + * +-----------------+ | | + * | context 15 | | data | + * +-----------------+ | | + * | ...... | \ | | + * +-----------------+ \____________ +-------------+ + * | context 1 | + * +-----------------+ + * | context 0 | + * +-----------------+ + * + * Each of the "contexts" is a chunk of memory that can be mmaped into user + * space. The context consists of 2 parts: + * + * - an instruction space that can be directly accessed by the user + * to issue GRU instructions and to check instruction status. + * + * - a data area that acts as normal RAM. + * + * User instructions contain virtual addresses of data to be accessed by the + * GRU. The GRU contains a TLB that is used to convert these user virtual + * addresses to physical addresses. + * + * The "system control" area of the GRU chiplet is used by the kernel driver + * to manage user contexts and to perform functions such as TLB dropin and + * purging. + * + * One context may be reserved for the kernel and used for cross-partition + * communication. The GRU will also be used to asynchronously zero out + * large blocks of memory (not currently implemented). + * + * * Tables: * * VDATA-VMA Data - Holds a few parameters. Head of linked list of @@ -190,14 +254,14 @@ struct gru_stats_s { #define GRU_STEAL_DELAY ((HZ * 200) / 1000) #define STAT(id) do { \ - if (options & OPT_STATS) \ + if (gru_options & OPT_STATS) \ atomic_long_inc(&gru_stats.id); \ } while (0) #ifdef CONFIG_SGI_GRU_DEBUG #define gru_dbg(dev, fmt, x...) \ do { \ - if (options & OPT_DPRINT) \ + if (gru_options & OPT_DPRINT) \ dev_dbg(dev, "%s: " fmt, __func__, x); \ } while (0) #else @@ -529,9 +593,9 @@ extern void gru_flush_all_tlb(struct gru_state *gru); extern int gru_proc_init(void); extern void gru_proc_exit(void); -extern unsigned long reserve_gru_cb_resources(struct gru_state *gru, +extern unsigned long gru_reserve_cb_resources(struct gru_state *gru, int cbr_au_count, char *cbmap); -extern unsigned long reserve_gru_ds_resources(struct gru_state *gru, +extern unsigned long gru_reserve_ds_resources(struct gru_state *gru, int dsr_au_count, char *dsmap); extern int gru_fault(struct vm_area_struct *, struct vm_fault *vmf); extern struct gru_mm_struct *gru_register_mmu_notifier(void); @@ -540,6 +604,6 @@ extern void gru_drop_mmu_notifier(struct gru_mm_struct *gms); extern void gru_flush_tlb_range(struct gru_mm_struct *gms, unsigned long start, unsigned long len); -extern unsigned long options; +extern unsigned long gru_options; #endif /* __GRUTABLES_H__ */ diff --git a/drivers/misc/sgi-gru/grutlbpurge.c b/drivers/misc/sgi-gru/grutlbpurge.c index bb6b0e64e10..bcfd5425e2e 100644 --- a/drivers/misc/sgi-gru/grutlbpurge.c +++ b/drivers/misc/sgi-gru/grutlbpurge.c @@ -242,7 +242,9 @@ static void gru_invalidate_range_end(struct mmu_notifier *mn, struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct, ms_notifier); - atomic_dec(&gms->ms_range_active); + /* ..._and_test() provides needed barrier */ + (void)atomic_dec_and_test(&gms->ms_range_active); + wake_up_all(&gms->ms_wait_queue); gru_dbg(grudev, "gms %p, start 0x%lx, end 0x%lx\n", gms, start, end); } -- cgit v1.2.3 From 355c54d2e70093f09910d2ecf343023aefc219e1 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:02 -0700 Subject: sgi-xp: define is_shub() and is_uv() macros Define the is_shub()/is_uv() macros if they've not already been defined. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xp.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index 03a87a307e3..83627eac412 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -25,6 +25,22 @@ #define DBUG_ON(condition) #endif +#ifndef is_shub1 +#define is_shub1() 0 +#endif + +#ifndef is_shub2 +#define is_shub2() 0 +#endif + +#ifndef is_shub +#define is_shub() (is_shub1() || is_shub2()) +#endif + +#ifndef is_uv +#define is_uv() 0 +#endif + /* * Define the maximum number of logically defined partitions the system * can support. It is constrained by the maximum number of hardware -- cgit v1.2.3 From da9705259848b968cdf6151b977334fe7b5b0461 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:03 -0700 Subject: sgi-xp: define xpSalError reason code Define xpSalError reason code. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xp.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index 83627eac412..21cb8a31def 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -249,8 +249,9 @@ enum xp_retval { xpDisconnected, /* 51: channel disconnected (closed) */ xpBteCopyError, /* 52: bte_copy() returned error */ + xpSalError, /* 53: sn SAL error */ - xpUnknownReason /* 53: unknown reason - must be last in enum */ + xpUnknownReason /* 54: unknown reason - must be last in enum */ }; /* -- cgit v1.2.3 From 78ce1bbe446e9b46dcd6c1e60a4768448a8ce355 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:03 -0700 Subject: sgi-xp: define BYTES_PER_WORD Add a BYTES_PER_WORD #define. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xp.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index 21cb8a31def..867fb4863d5 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -19,6 +19,9 @@ #include #include +/* >>> Add this #define to some linux header file some day. */ +#define BYTES_PER_WORD sizeof(void *) + #ifdef USE_DBUG_ON #define DBUG_ON(condition) BUG_ON(condition) #else -- cgit v1.2.3 From bc63d387e4f5dbbe4ea0c5ade862c38073fd7fa3 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:04 -0700 Subject: sgi-xp: support runtime selection of xp_max_npartitions Support runtime selection of the max number of partitions based on the hardware being run on. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/Makefile | 3 +- drivers/misc/sgi-xp/xp.h | 53 ++++++++++++------- drivers/misc/sgi-xp/xp_main.c | 84 ++++++++++++----------------- drivers/misc/sgi-xp/xp_sn2.c | 92 ++++++++++++++++++++++++++++++++ drivers/misc/sgi-xp/xp_uv.c | 30 +++++++++++ drivers/misc/sgi-xp/xpc.h | 12 +++-- drivers/misc/sgi-xp/xpc_channel.c | 20 +++---- drivers/misc/sgi-xp/xpc_main.c | 103 +++++++++++++++++------------------- drivers/misc/sgi-xp/xpc_partition.c | 16 ++---- drivers/misc/sgi-xp/xpnet.c | 4 +- 10 files changed, 266 insertions(+), 151 deletions(-) create mode 100644 drivers/misc/sgi-xp/xp_sn2.c create mode 100644 drivers/misc/sgi-xp/xp_uv.c (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/Makefile b/drivers/misc/sgi-xp/Makefile index b6e40a7958c..b50f2921781 100644 --- a/drivers/misc/sgi-xp/Makefile +++ b/drivers/misc/sgi-xp/Makefile @@ -3,7 +3,8 @@ # obj-$(CONFIG_SGI_XP) += xp.o -xp-y := xp_main.o xp_nofault.o +xp-y := xp_main.o xp_uv.o +xp-$(CONFIG_IA64) += xp_sn2.o xp_nofault.o obj-$(CONFIG_SGI_XP) += xpc.o xpc-y := xpc_main.o xpc_channel.o xpc_partition.o diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index 867fb4863d5..51087e11188 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -18,6 +18,9 @@ #include #include #include +#ifdef CONFIG_IA64 +#include +#endif /* >>> Add this #define to some linux header file some day. */ #define BYTES_PER_WORD sizeof(void *) @@ -45,17 +48,18 @@ #endif /* - * Define the maximum number of logically defined partitions the system - * can support. It is constrained by the maximum number of hardware - * partitionable regions. The term 'region' in this context refers to the - * minimum number of nodes that can comprise an access protection grouping. - * The access protection is in regards to memory, IPI and IOI. + * Define the maximum number of partitions the system can possibly support. + * It is based on the maximum number of hardware partitionable regions. The + * term 'region' in this context refers to the minimum number of nodes that + * can comprise an access protection grouping. The access protection is in + * regards to memory, IPI and IOI. * * The maximum number of hardware partitionable regions is equal to the * maximum number of nodes in the entire system divided by the minimum number * of nodes that comprise an access protection grouping. */ -#define XP_MAX_PARTITIONS 64 +#define XP_MAX_NPARTITIONS_SN2 64 +#define XP_MAX_NPARTITIONS_UV 256 /* * Define the number of u64s required to represent all the C-brick nasids @@ -112,24 +116,28 @@ xp_bte_copy(u64 src, u64 vdst, u64 len, u64 mode, void *notification) * other partition that is currently up. Over these channels, kernel-level * `users' can communicate with their counterparts on the other partitions. * - * The maxinum number of channels is limited to eight. For performance reasons, - * the internal cross partition structures require sixteen bytes per channel, - * and eight allows all of this interface-shared info to fit in one cache line. +>>> The following described limitation of a max of eight channels possible +>>> pertains only to ia64-sn2. THIS ISN'T TRUE SINCE I'M PLANNING TO JUST +>>> TIE INTO THE EXISTING MECHANISM ONCE THE CHANNEL MESSAGES ARE RECEIVED. +>>> THE 128-BYTE CACHELINE PERFORMANCE ISSUE IS TIED TO IA64-SN2. * - * XPC_NCHANNELS reflects the total number of channels currently defined. * If the need for additional channels arises, one can simply increase - * XPC_NCHANNELS accordingly. If the day should come where that number - * exceeds the MAXIMUM number of channels allowed (eight), then one will need - * to make changes to the XPC code to allow for this. + * XPC_MAX_NCHANNELS accordingly. If the day should come where that number + * exceeds the absolute MAXIMUM number of channels possible (eight), then one + * will need to make changes to the XPC code to accommodate for this. + * + * The absolute maximum number of channels possible is currently limited to + * eight for performance reasons. The internal cross partition structures + * require sixteen bytes per channel, and eight allows all of this + * interface-shared info to fit in one 128-byte cacheline. */ #define XPC_MEM_CHANNEL 0 /* memory channel number */ #define XPC_NET_CHANNEL 1 /* network channel number */ -#define XPC_NCHANNELS 2 /* #of defined channels */ -#define XPC_MAX_NCHANNELS 8 /* max #of channels allowed */ +#define XPC_MAX_NCHANNELS 2 /* max #of channels allowed */ -#if XPC_NCHANNELS > XPC_MAX_NCHANNELS -#error XPC_NCHANNELS exceeds MAXIMUM allowed. +#if XPC_MAX_NCHANNELS > 8 +#error XPC_MAX_NCHANNELS exceeds absolute MAXIMUM possible. #endif /* @@ -254,7 +262,8 @@ enum xp_retval { xpBteCopyError, /* 52: bte_copy() returned error */ xpSalError, /* 53: sn SAL error */ - xpUnknownReason /* 54: unknown reason - must be last in enum */ + xpUnsupported, /* 54: unsupported functionality or resource */ + xpUnknownReason /* 55: unknown reason - must be last in enum */ }; /* @@ -397,8 +406,16 @@ xpc_partid_to_nasids(short partid, void *nasids) return xpc_interface.partid_to_nasids(partid, nasids); } +extern short xp_max_npartitions; + extern u64 xp_nofault_PIOR_target; extern int xp_nofault_PIOR(void *); extern int xp_error_PIOR(void); +extern struct device *xp; +extern enum xp_retval xp_init_sn2(void); +extern enum xp_retval xp_init_uv(void); +extern void xp_exit_sn2(void); +extern void xp_exit_uv(void); + #endif /* _DRIVERS_MISC_SGIXP_XP_H */ diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c index 196480b691a..c5cec606377 100644 --- a/drivers/misc/sgi-xp/xp_main.c +++ b/drivers/misc/sgi-xp/xp_main.c @@ -15,28 +15,32 @@ */ #include -#include #include -#include -#include -#include +#include #include "xp.h" -/* - * The export of xp_nofault_PIOR needs to happen here since it is defined - * in drivers/misc/sgi-xp/xp_nofault.S. The target of the nofault read is - * defined here. - */ -EXPORT_SYMBOL_GPL(xp_nofault_PIOR); +/* define the XP debug device structures to be used with dev_dbg() et al */ -u64 xp_nofault_PIOR_target; -EXPORT_SYMBOL_GPL(xp_nofault_PIOR_target); +struct device_driver xp_dbg_name = { + .name = "xp" +}; + +struct device xp_dbg_subname = { + .bus_id = {0}, /* set to "" */ + .driver = &xp_dbg_name +}; + +struct device *xp = &xp_dbg_subname; + +/* max #of partitions possible */ +short xp_max_npartitions; +EXPORT_SYMBOL_GPL(xp_max_npartitions); /* * xpc_registrations[] keeps track of xpc_connect()'s done by the kernel-level * users of XPC. */ -struct xpc_registration xpc_registrations[XPC_NCHANNELS]; +struct xpc_registration xpc_registrations[XPC_MAX_NCHANNELS]; EXPORT_SYMBOL_GPL(xpc_registrations); /* @@ -135,7 +139,7 @@ xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size, { struct xpc_registration *registration; - DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); + DBUG_ON(ch_number < 0 || ch_number >= XPC_MAX_NCHANNELS); DBUG_ON(payload_size == 0 || nentries == 0); DBUG_ON(func == NULL); DBUG_ON(assigned_limit == 0 || idle_limit > assigned_limit); @@ -185,7 +189,7 @@ xpc_disconnect(int ch_number) { struct xpc_registration *registration; - DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); + DBUG_ON(ch_number < 0 || ch_number >= XPC_MAX_NCHANNELS); registration = &xpc_registrations[ch_number]; @@ -221,39 +225,21 @@ EXPORT_SYMBOL_GPL(xpc_disconnect); int __init xp_init(void) { - int ret, ch_number; - u64 func_addr = *(u64 *)xp_nofault_PIOR; - u64 err_func_addr = *(u64 *)xp_error_PIOR; - - if (!ia64_platform_is("sn2")) - return -ENODEV; + enum xp_retval ret; + int ch_number; - /* - * Register a nofault code region which performs a cross-partition - * PIO read. If the PIO read times out, the MCA handler will consume - * the error and return to a kernel-provided instruction to indicate - * an error. This PIO read exists because it is guaranteed to timeout - * if the destination is down (AMO operations do not timeout on at - * least some CPUs on Shubs <= v1.2, which unfortunately we have to - * work around). - */ - ret = sn_register_nofault_code(func_addr, err_func_addr, err_func_addr, - 1, 1); - if (ret != 0) { - printk(KERN_ERR "XP: can't register nofault code, error=%d\n", - ret); - } - /* - * Setup the nofault PIO read target. (There is no special reason why - * SH_IPI_ACCESS was selected.) - */ - if (is_shub2()) - xp_nofault_PIOR_target = SH2_IPI_ACCESS0; + if (is_shub()) + ret = xp_init_sn2(); + else if (is_uv()) + ret = xp_init_uv(); else - xp_nofault_PIOR_target = SH1_IPI_ACCESS; + ret = xpUnsupported; + + if (ret != xpSuccess) + return -ENODEV; /* initialize the connection registration mutex */ - for (ch_number = 0; ch_number < XPC_NCHANNELS; ch_number++) + for (ch_number = 0; ch_number < XPC_MAX_NCHANNELS; ch_number++) mutex_init(&xpc_registrations[ch_number].mutex); return 0; @@ -264,12 +250,10 @@ module_init(xp_init); void __exit xp_exit(void) { - u64 func_addr = *(u64 *)xp_nofault_PIOR; - u64 err_func_addr = *(u64 *)xp_error_PIOR; - - /* unregister the PIO read nofault code region */ - (void)sn_register_nofault_code(func_addr, err_func_addr, - err_func_addr, 1, 0); + if (is_shub()) + xp_exit_sn2(); + else if (is_uv()) + xp_exit_uv(); } module_exit(xp_exit); diff --git a/drivers/misc/sgi-xp/xp_sn2.c b/drivers/misc/sgi-xp/xp_sn2.c new file mode 100644 index 00000000000..b92579356a6 --- /dev/null +++ b/drivers/misc/sgi-xp/xp_sn2.c @@ -0,0 +1,92 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + */ + +/* + * Cross Partition (XP) sn2-based functions. + * + * Architecture specific implementation of common functions. + */ + +#include +#include +#include "xp.h" + +/* + * The export of xp_nofault_PIOR needs to happen here since it is defined + * in drivers/misc/sgi-xp/xp_nofault.S. The target of the nofault read is + * defined here. + */ +EXPORT_SYMBOL_GPL(xp_nofault_PIOR); + +u64 xp_nofault_PIOR_target; +EXPORT_SYMBOL_GPL(xp_nofault_PIOR_target); + +/* + * Register a nofault code region which performs a cross-partition PIO read. + * If the PIO read times out, the MCA handler will consume the error and + * return to a kernel-provided instruction to indicate an error. This PIO read + * exists because it is guaranteed to timeout if the destination is down + * (AMO operations do not timeout on at least some CPUs on Shubs <= v1.2, + * which unfortunately we have to work around). + */ +static enum xp_retval +xp_register_nofault_code_sn2(void) +{ + int ret; + u64 func_addr; + u64 err_func_addr; + + func_addr = *(u64 *)xp_nofault_PIOR; + err_func_addr = *(u64 *)xp_error_PIOR; + ret = sn_register_nofault_code(func_addr, err_func_addr, err_func_addr, + 1, 1); + if (ret != 0) { + dev_err(xp, "can't register nofault code, error=%d\n", ret); + return xpSalError; + } + /* + * Setup the nofault PIO read target. (There is no special reason why + * SH_IPI_ACCESS was selected.) + */ + if (is_shub1()) + xp_nofault_PIOR_target = SH1_IPI_ACCESS; + else if (is_shub2()) + xp_nofault_PIOR_target = SH2_IPI_ACCESS0; + + return xpSuccess; +} + +void +xp_unregister_nofault_code_sn2(void) +{ + u64 func_addr = *(u64 *)xp_nofault_PIOR; + u64 err_func_addr = *(u64 *)xp_error_PIOR; + + /* unregister the PIO read nofault code region */ + (void)sn_register_nofault_code(func_addr, err_func_addr, + err_func_addr, 1, 0); +} + +enum xp_retval +xp_init_sn2(void) +{ + BUG_ON(!is_shub()); + + xp_max_npartitions = XP_MAX_NPARTITIONS_SN2; + + return xp_register_nofault_code_sn2(); +} + +void +xp_exit_sn2(void) +{ + BUG_ON(!is_shub()); + + xp_unregister_nofault_code_sn2(); +} + diff --git a/drivers/misc/sgi-xp/xp_uv.c b/drivers/misc/sgi-xp/xp_uv.c new file mode 100644 index 00000000000..30888be2cdb --- /dev/null +++ b/drivers/misc/sgi-xp/xp_uv.c @@ -0,0 +1,30 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + */ + +/* + * Cross Partition (XP) uv-based functions. + * + * Architecture specific implementation of common functions. + * + */ + +#include "xp.h" + +enum xp_retval +xp_init_uv(void) +{ + BUG_ON(!is_uv()); + + xp_max_npartitions = XP_MAX_NPARTITIONS_UV; +} + +void +xp_exit_uv(void) +{ + BUG_ON(!is_uv()); +} diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 11ac267ed68..0f2affd01df 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -210,7 +210,7 @@ xpc_disallow_hb(short partid, struct xpc_vars *vars) * the XPC running on the remote partition). */ #define XPC_NOTIFY_IRQ_AMOS 0 -#define XPC_ACTIVATE_IRQ_AMOS (XPC_NOTIFY_IRQ_AMOS + XP_MAX_PARTITIONS) +#define XPC_ACTIVATE_IRQ_AMOS (XPC_NOTIFY_IRQ_AMOS + XP_MAX_NPARTITIONS_SN2) #define XPC_ENGAGED_PARTITIONS_AMO (XPC_ACTIVATE_IRQ_AMOS + XP_NASID_MASK_WORDS) #define XPC_DISENGAGE_REQUEST_AMO (XPC_ENGAGED_PARTITIONS_AMO + 1) @@ -285,7 +285,7 @@ struct xpc_gp { }; #define XPC_GP_SIZE \ - L1_CACHE_ALIGN(sizeof(struct xpc_gp) * XPC_NCHANNELS) + L1_CACHE_ALIGN(sizeof(struct xpc_gp) * XPC_MAX_NCHANNELS) /* * Define a structure that contains arguments associated with opening and @@ -300,7 +300,8 @@ struct xpc_openclose_args { }; #define XPC_OPENCLOSE_ARGS_SIZE \ - L1_CACHE_ALIGN(sizeof(struct xpc_openclose_args) * XPC_NCHANNELS) + L1_CACHE_ALIGN(sizeof(struct xpc_openclose_args) * \ + XPC_MAX_NCHANNELS) /* struct xpc_msg flags */ @@ -637,7 +638,7 @@ extern int xpc_exiting; extern struct xpc_vars *xpc_vars; extern struct xpc_rsvd_page *xpc_rsvd_page; extern struct xpc_vars_part *xpc_vars_part; -extern struct xpc_partition xpc_partitions[XP_MAX_PARTITIONS + 1]; +extern struct xpc_partition *xpc_partitions; extern char *xpc_remote_copy_buffer; extern void *xpc_remote_copy_buffer_base; extern void *xpc_kmalloc_cacheline_aligned(size_t, gfp_t, void **); @@ -1104,13 +1105,14 @@ xpc_IPI_send_local_msgrequest(struct xpc_channel *ch) } /* +>>> this block comment needs to be moved and re-written. * Memory for XPC's AMO variables is allocated by the MSPEC driver. These * pages are located in the lowest granule. The lowest granule uses 4k pages * for cached references and an alternate TLB handler to never provide a * cacheable mapping for the entire region. This will prevent speculative * reading of cached copies of our lines from being issued which will cause * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64 - * AMO variables (based on XP_MAX_PARTITIONS) for message notification and an + * AMO variables (based on xp_max_npartitions) for message notification and an * additional 128 AMO variables (based on XP_NASID_MASK_WORDS) for partition * activation and 2 AMO variables for partition deactivation. */ diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index 9c90c2d55c0..12d8eb6957a 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -110,14 +110,14 @@ xpc_setup_infrastructure(struct xpc_partition *part) * Allocate all of the channel structures as a contiguous chunk of * memory. */ - part->channels = kzalloc(sizeof(struct xpc_channel) * XPC_NCHANNELS, + part->channels = kzalloc(sizeof(struct xpc_channel) * XPC_MAX_NCHANNELS, GFP_KERNEL); if (part->channels == NULL) { dev_err(xpc_chan, "can't get memory for channels\n"); return xpNoMemory; } - part->nchannels = XPC_NCHANNELS; + part->nchannels = XPC_MAX_NCHANNELS; /* allocate all the required GET/PUT values */ @@ -1432,9 +1432,9 @@ xpc_initiate_connect(int ch_number) struct xpc_partition *part; struct xpc_channel *ch; - DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); + DBUG_ON(ch_number < 0 || ch_number >= XPC_MAX_NCHANNELS); - for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + for (partid = 0; partid < xp_max_npartitions; partid++) { part = &xpc_partitions[partid]; if (xpc_part_ref(part)) { @@ -1488,10 +1488,10 @@ xpc_initiate_disconnect(int ch_number) struct xpc_partition *part; struct xpc_channel *ch; - DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); + DBUG_ON(ch_number < 0 || ch_number >= XPC_MAX_NCHANNELS); /* initiate the channel disconnect for every active partition */ - for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + for (partid = 0; partid < xp_max_npartitions; partid++) { part = &xpc_partitions[partid]; if (xpc_part_ref(part)) { @@ -1734,7 +1734,7 @@ xpc_initiate_allocate(short partid, int ch_number, u32 flags, void **payload) enum xp_retval ret = xpUnknownReason; struct xpc_msg *msg = NULL; - DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); + DBUG_ON(partid < 0 || partid >= xp_max_npartitions); DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); *payload = NULL; @@ -1918,7 +1918,7 @@ xpc_initiate_send(short partid, int ch_number, void *payload) dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *)msg, partid, ch_number); - DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); + DBUG_ON(partid < 0 || partid >= xp_max_npartitions); DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); DBUG_ON(msg == NULL); @@ -1968,7 +1968,7 @@ xpc_initiate_send_notify(short partid, int ch_number, void *payload, dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *)msg, partid, ch_number); - DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); + DBUG_ON(partid < 0 || partid >= xp_max_npartitions); DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); DBUG_ON(msg == NULL); DBUG_ON(func == NULL); @@ -2210,7 +2210,7 @@ xpc_initiate_received(short partid, int ch_number, void *payload) struct xpc_msg *msg = XPC_MSG_ADDRESS(payload); s64 get, msg_number = msg->number; - DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); + DBUG_ON(partid < 0 || partid >= xp_max_npartitions); DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); ch = &part->channels[ch_number]; diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index c3b4227f48a..a05c7c7da22 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -433,7 +433,7 @@ xpc_activating(void *__partid) struct xpc_partition *part = &xpc_partitions[partid]; unsigned long irq_flags; - DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); + DBUG_ON(partid < 0 || partid >= xp_max_npartitions); spin_lock_irqsave(&part->act_lock, irq_flags); @@ -544,7 +544,7 @@ xpc_notify_IRQ_handler(int irq, void *dev_id) short partid = (short)(u64)dev_id; struct xpc_partition *part = &xpc_partitions[partid]; - DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); + DBUG_ON(partid < 0 || partid >= xp_max_npartitions); if (xpc_part_ref(part)) { xpc_check_for_channel_activity(part); @@ -815,7 +815,7 @@ xpc_disconnect_wait(int ch_number) int wakeup_channel_mgr; /* now wait for all callouts to the caller's function to cease */ - for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + for (partid = 0; partid < xp_max_npartitions; partid++) { part = &xpc_partitions[partid]; if (!xpc_part_ref(part)) @@ -895,7 +895,7 @@ xpc_do_exit(enum xp_retval reason) do { active_part_count = 0; - for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + for (partid = 0; partid < xp_max_npartitions; partid++) { part = &xpc_partitions[partid]; if (xpc_partition_disengaged(part) && @@ -956,11 +956,8 @@ xpc_do_exit(enum xp_retval reason) DBUG_ON(xpc_vars->heartbeating_to_mask != 0); if (reason == xpUnloading) { - /* take ourselves off of the reboot_notifier_list */ - (void)unregister_reboot_notifier(&xpc_reboot_notifier); - - /* take ourselves off of the die_notifier list */ (void)unregister_die_notifier(&xpc_die_notifier); + (void)unregister_reboot_notifier(&xpc_reboot_notifier); } /* close down protections for IPI operations */ @@ -972,6 +969,7 @@ xpc_do_exit(enum xp_retval reason) if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); + kfree(xpc_partitions); kfree(xpc_remote_copy_buffer_base); } @@ -1017,7 +1015,7 @@ xpc_die_disengage(void) xpc_vars->heartbeating_to_mask = 0; /* indicate we're deactivated */ - for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + for (partid = 0; partid < xp_max_npartitions; partid++) { part = &xpc_partitions[partid]; if (!XPC_SUPPORTS_DISENGAGE_REQUEST(part-> @@ -1053,7 +1051,8 @@ xpc_die_disengage(void) time = rtc_time(); if (time >= disengage_request_timeout) { - for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + for (partid = 0; partid < xp_max_npartitions; + partid++) { if (engaged & (1UL << partid)) { dev_info(xpc_part, "disengage from " "remote partition %d timed " @@ -1132,18 +1131,26 @@ xpc_init(void) if (!ia64_platform_is("sn2")) return -ENODEV; + snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part"); + snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan"); + buf_size = max(XPC_RP_VARS_SIZE, XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES); xpc_remote_copy_buffer = xpc_kmalloc_cacheline_aligned(buf_size, GFP_KERNEL, &xpc_remote_copy_buffer_base); - if (xpc_remote_copy_buffer == NULL) + if (xpc_remote_copy_buffer == NULL) { + dev_err(xpc_part, "can't get memory for remote copy buffer\n"); return -ENOMEM; + } - snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part"); - snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan"); - - xpc_sysctl = register_sysctl_table(xpc_sys_dir); + xpc_partitions = kzalloc(sizeof(struct xpc_partition) * + xp_max_npartitions, GFP_KERNEL); + if (xpc_partitions == NULL) { + dev_err(xpc_part, "can't get memory for partition structure\n"); + ret = -ENOMEM; + goto out_1; + } /* * The first few fields of each entry of xpc_partitions[] need to @@ -1153,7 +1160,7 @@ xpc_init(void) * ENTRIES ARE MEANINGFUL UNTIL AFTER AN ENTRY'S CORRESPONDING * PARTITION HAS BEEN ACTIVATED. */ - for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + for (partid = 0; partid < xp_max_npartitions; partid++) { part = &xpc_partitions[partid]; DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part)); @@ -1173,6 +1180,8 @@ xpc_init(void) atomic_set(&part->references, 0); } + xpc_sysctl = register_sysctl_table(xpc_sys_dir); + /* * Open up protections for IPI operations (and AMO operations on * Shub 1.1 systems). @@ -1196,14 +1205,8 @@ xpc_init(void) if (ret != 0) { dev_err(xpc_part, "can't register ACTIVATE IRQ handler, " "errno=%d\n", -ret); - - xpc_restrict_IPI_ops(); - - if (xpc_sysctl) - unregister_sysctl_table(xpc_sysctl); - - kfree(xpc_remote_copy_buffer_base); - return -EBUSY; + ret = -EBUSY; + goto out_2; } /* @@ -1213,16 +1216,9 @@ xpc_init(void) */ xpc_rsvd_page = xpc_rsvd_page_init(); if (xpc_rsvd_page == NULL) { - dev_err(xpc_part, "could not setup our reserved page\n"); - - free_irq(SGI_XPC_ACTIVATE, NULL); - xpc_restrict_IPI_ops(); - - if (xpc_sysctl) - unregister_sysctl_table(xpc_sysctl); - - kfree(xpc_remote_copy_buffer_base); - return -EBUSY; + dev_err(xpc_part, "can't setup our reserved page\n"); + ret = -EBUSY; + goto out_3; } /* add ourselves to the reboot_notifier_list */ @@ -1245,25 +1241,8 @@ xpc_init(void) kthread = kthread_run(xpc_hb_checker, NULL, XPC_HB_CHECK_THREAD_NAME); if (IS_ERR(kthread)) { dev_err(xpc_part, "failed while forking hb check thread\n"); - - /* indicate to others that our reserved page is uninitialized */ - xpc_rsvd_page->vars_pa = 0; - - /* take ourselves off of the reboot_notifier_list */ - (void)unregister_reboot_notifier(&xpc_reboot_notifier); - - /* take ourselves off of the die_notifier list */ - (void)unregister_die_notifier(&xpc_die_notifier); - - del_timer_sync(&xpc_hb_timer); - free_irq(SGI_XPC_ACTIVATE, NULL); - xpc_restrict_IPI_ops(); - - if (xpc_sysctl) - unregister_sysctl_table(xpc_sysctl); - - kfree(xpc_remote_copy_buffer_base); - return -EBUSY; + ret = -EBUSY; + goto out_4; } /* @@ -1290,6 +1269,24 @@ xpc_init(void) xpc_initiate_partid_to_nasids); return 0; + + /* initialization was not successful */ +out_4: + /* indicate to others that our reserved page is uninitialized */ + xpc_rsvd_page->vars_pa = 0; + del_timer_sync(&xpc_hb_timer); + (void)unregister_die_notifier(&xpc_die_notifier); + (void)unregister_reboot_notifier(&xpc_reboot_notifier); +out_3: + free_irq(SGI_XPC_ACTIVATE, NULL); +out_2: + xpc_restrict_IPI_ops(); + if (xpc_sysctl) + unregister_sysctl_table(xpc_sysctl); + kfree(xpc_partitions); +out_1: + kfree(xpc_remote_copy_buffer_base); + return ret; } module_init(xpc_init); diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 7dd4b5812c4..02a858eddd8 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -51,13 +51,7 @@ struct xpc_vars_part *xpc_vars_part; static int xp_nasid_mask_bytes; /* actual size in bytes of nasid mask */ static int xp_nasid_mask_words; /* actual size in words of nasid mask */ -/* - * For performance reasons, each entry of xpc_partitions[] is cacheline - * aligned. And xpc_partitions[] is padded with an additional entry at the - * end so that the last legitimate entry doesn't share its cacheline with - * another variable. - */ -struct xpc_partition xpc_partitions[XP_MAX_PARTITIONS + 1]; +struct xpc_partition *xpc_partitions; /* * Generic buffer used to store a local copy of portions of a remote @@ -261,7 +255,7 @@ xpc_rsvd_page_init(void) /* clear xpc_vars_part */ memset((u64 *)xpc_vars_part, 0, sizeof(struct xpc_vars_part) * - XP_MAX_PARTITIONS); + xp_max_npartitions); /* initialize the activate IRQ related AMO variables */ for (i = 0; i < xp_nasid_mask_words; i++) @@ -408,7 +402,7 @@ xpc_check_remote_hb(void) remote_vars = (struct xpc_vars *)xpc_remote_copy_buffer; - for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + for (partid = 0; partid < xp_max_npartitions; partid++) { if (xpc_exiting) break; @@ -487,10 +481,8 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, /* check that the partid is for another partition */ - if (remote_rp->partid < 1 || - remote_rp->partid > (XP_MAX_PARTITIONS - 1)) { + if (remote_rp->partid < 0 || remote_rp->partid >= xp_max_npartitions) return xpInvalidPartid; - } if (remote_rp->partid == sn_partition_id) return xpLocalPartid; diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 822dc8e8d7f..cc252f201b2 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -287,7 +287,7 @@ xpnet_connection_activity(enum xp_retval reason, short partid, int channel, { long bp; - DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); + DBUG_ON(partid < 0 || partid >= xp_max_npartitions); DBUG_ON(channel != XPC_NET_CHANNEL); switch (reason) { @@ -513,7 +513,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) /* * Main send loop. */ - for (dest_partid = 1; dp && dest_partid < XP_MAX_PARTITIONS; + for (dest_partid = 0; dp && dest_partid < xp_max_npartitions; dest_partid++) { if (!(dp & (1UL << (dest_partid - 1)))) { -- cgit v1.2.3 From 908787db9b95f548270af18d83d62b9d2020ca10 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:05 -0700 Subject: sgi-xp: create a common xp_remote_memcpy() function Create a common remote memcpy function that maps to what the hardware booted supports. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xp.h | 43 ++--------------------------- drivers/misc/sgi-xp/xp_main.c | 3 ++ drivers/misc/sgi-xp/xp_sn2.c | 46 +++++++++++++++++++++++++++++++ drivers/misc/sgi-xp/xp_uv.c | 11 ++++++++ drivers/misc/sgi-xp/xpc.h | 7 ----- drivers/misc/sgi-xp/xpc_channel.c | 20 ++++++-------- drivers/misc/sgi-xp/xpc_partition.c | 55 ++++++++++++++++--------------------- drivers/misc/sgi-xp/xpnet.c | 28 +++++++++---------- 8 files changed, 107 insertions(+), 106 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index 51087e11188..c42196a1a6b 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -17,7 +17,6 @@ #include #include #include -#include #ifdef CONFIG_IA64 #include #endif @@ -71,46 +70,6 @@ #define XP_NASID_MASK_BYTES ((XP_MAX_PHYSNODE_ID + 7) / 8) #define XP_NASID_MASK_WORDS ((XP_MAX_PHYSNODE_ID + 63) / 64) -/* - * Wrapper for bte_copy() that should it return a failure status will retry - * the bte_copy() once in the hope that the failure was due to a temporary - * aberration (i.e., the link going down temporarily). - * - * src - physical address of the source of the transfer. - * vdst - virtual address of the destination of the transfer. - * len - number of bytes to transfer from source to destination. - * mode - see bte_copy() for definition. - * notification - see bte_copy() for definition. - * - * Note: xp_bte_copy() should never be called while holding a spinlock. - */ -static inline bte_result_t -xp_bte_copy(u64 src, u64 vdst, u64 len, u64 mode, void *notification) -{ - bte_result_t ret; - u64 pdst = ia64_tpa(vdst); - - /* - * Ensure that the physically mapped memory is contiguous. - * - * We do this by ensuring that the memory is from region 7 only. - * If the need should arise to use memory from one of the other - * regions, then modify the BUG_ON() statement to ensure that the - * memory from that region is always physically contiguous. - */ - BUG_ON(REGION_NUMBER(vdst) != RGN_KERNEL); - - ret = bte_copy(src, pdst, len, mode, notification); - if ((ret != BTE_SUCCESS) && BTE_ERROR_RETRY(ret)) { - if (!in_interrupt()) - cond_resched(); - - ret = bte_copy(src, pdst, len, mode, notification); - } - - return ret; -} - /* * XPC establishes channel connections between the local partition and any * other partition that is currently up. Over these channels, kernel-level @@ -408,6 +367,8 @@ xpc_partid_to_nasids(short partid, void *nasids) extern short xp_max_npartitions; +extern enum xp_retval (*xp_remote_memcpy) (void *, const void *, size_t); + extern u64 xp_nofault_PIOR_target; extern int xp_nofault_PIOR(void *); extern int xp_error_PIOR(void); diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c index c5cec606377..6f25613b27e 100644 --- a/drivers/misc/sgi-xp/xp_main.c +++ b/drivers/misc/sgi-xp/xp_main.c @@ -36,6 +36,9 @@ struct device *xp = &xp_dbg_subname; short xp_max_npartitions; EXPORT_SYMBOL_GPL(xp_max_npartitions); +enum xp_retval (*xp_remote_memcpy) (void *dst, const void *src, size_t len); +EXPORT_SYMBOL_GPL(xp_remote_memcpy); + /* * xpc_registrations[] keeps track of xpc_connect()'s done by the kernel-level * users of XPC. diff --git a/drivers/misc/sgi-xp/xp_sn2.c b/drivers/misc/sgi-xp/xp_sn2.c index b92579356a6..3d553fa73f4 100644 --- a/drivers/misc/sgi-xp/xp_sn2.c +++ b/drivers/misc/sgi-xp/xp_sn2.c @@ -13,6 +13,7 @@ */ #include +#include #include #include "xp.h" @@ -72,6 +73,49 @@ xp_unregister_nofault_code_sn2(void) err_func_addr, 1, 0); } +/* + * Wrapper for bte_copy(). + * + * vdst - virtual address of the destination of the transfer. + * psrc - physical address of the source of the transfer. + * len - number of bytes to transfer from source to destination. + * + * Note: xp_remote_memcpy_sn2() should never be called while holding a spinlock. + */ +static enum xp_retval +xp_remote_memcpy_sn2(void *vdst, const void *psrc, size_t len) +{ + bte_result_t ret; + u64 pdst = ia64_tpa(vdst); + /* >>> What are the rules governing the src and dst addresses passed in? + * >>> Currently we're assuming that dst is a virtual address and src + * >>> is a physical address, is this appropriate? Can we allow them to + * >>> be whatever and we make the change here without damaging the + * >>> addresses? + */ + + /* + * Ensure that the physically mapped memory is contiguous. + * + * We do this by ensuring that the memory is from region 7 only. + * If the need should arise to use memory from one of the other + * regions, then modify the BUG_ON() statement to ensure that the + * memory from that region is always physically contiguous. + */ + BUG_ON(REGION_NUMBER(vdst) != RGN_KERNEL); + + ret = bte_copy((u64)psrc, pdst, len, (BTE_NOTIFY | BTE_WACQUIRE), NULL); + if (ret == BTE_SUCCESS) + return xpSuccess; + + if (is_shub2()) + dev_err(xp, "bte_copy() on shub2 failed, error=0x%x\n", ret); + else + dev_err(xp, "bte_copy() failed, error=%d\n", ret); + + return xpBteCopyError; +} + enum xp_retval xp_init_sn2(void) { @@ -79,6 +123,8 @@ xp_init_sn2(void) xp_max_npartitions = XP_MAX_NPARTITIONS_SN2; + xp_remote_memcpy = xp_remote_memcpy_sn2; + return xp_register_nofault_code_sn2(); } diff --git a/drivers/misc/sgi-xp/xp_uv.c b/drivers/misc/sgi-xp/xp_uv.c index 30888be2cdb..dca519fdef9 100644 --- a/drivers/misc/sgi-xp/xp_uv.c +++ b/drivers/misc/sgi-xp/xp_uv.c @@ -15,12 +15,23 @@ #include "xp.h" +static enum xp_retval +xp_remote_memcpy_uv(void *vdst, const void *psrc, size_t len) +{ + /* >>> this function needs fleshing out */ + return xpUnsupported; +} + enum xp_retval xp_init_uv(void) { BUG_ON(!is_uv()); xp_max_npartitions = XP_MAX_NPARTITIONS_UV; + + xp_remote_memcpy = xp_remote_memcpy_uv; + + return xpSuccess; } void diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 0f2affd01df..60388bed770 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -1125,12 +1124,6 @@ xpc_IPI_init(int index) return amo; } -static inline enum xp_retval -xpc_map_bte_errors(bte_result_t error) -{ - return ((error == BTE_SUCCESS) ? xpSuccess : xpBteCopyError); -} - /* * Check to see if there is any channel activity to/from the specified * partition. diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index 12d8eb6957a..9e79ad7eafe 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include "xpc.h" @@ -252,13 +251,13 @@ xpc_setup_infrastructure(struct xpc_partition *part) * * src must be a cacheline aligned physical address on the remote partition. * dst must be a cacheline aligned virtual address on this partition. - * cnt must be an cacheline sized + * cnt must be cacheline sized */ static enum xp_retval xpc_pull_remote_cachelines(struct xpc_partition *part, void *dst, const void *src, size_t cnt) { - bte_result_t bte_ret; + enum xp_retval ret; DBUG_ON((u64)src != L1_CACHE_ALIGN((u64)src)); DBUG_ON((u64)dst != L1_CACHE_ALIGN((u64)dst)); @@ -267,15 +266,12 @@ xpc_pull_remote_cachelines(struct xpc_partition *part, void *dst, if (part->act_state == XPC_P_DEACTIVATING) return part->reason; - bte_ret = xp_bte_copy((u64)src, (u64)dst, (u64)cnt, - (BTE_NORMAL | BTE_WACQUIRE), NULL); - if (bte_ret == BTE_SUCCESS) - return xpSuccess; - - dev_dbg(xpc_chan, "xp_bte_copy() from partition %d failed, ret=%d\n", - XPC_PARTID(part), bte_ret); - - return xpc_map_bte_errors(bte_ret); + ret = xp_remote_memcpy(dst, src, cnt); + if (ret != xpSuccess) { + dev_dbg(xpc_chan, "xp_remote_memcpy() from partition %d failed," + " ret=%d\n", XPC_PARTID(part), ret); + } + return ret; } /* diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 02a858eddd8..6c82f205097 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -92,7 +91,7 @@ xpc_kmalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) static u64 xpc_get_rsvd_page_pa(int nasid) { - bte_result_t bte_res; + enum xp_retval ret; s64 status; u64 cookie = 0; u64 rp_pa = nasid; /* seed with nasid */ @@ -113,6 +112,7 @@ xpc_get_rsvd_page_pa(int nasid) if (status != SALRET_MORE_PASSES) break; + /* >>> L1_CACHE_ALIGN() is only a sn2-bte_copy requirement */ if (L1_CACHE_ALIGN(len) > buf_len) { kfree(buf_base); buf_len = L1_CACHE_ALIGN(len); @@ -127,10 +127,9 @@ xpc_get_rsvd_page_pa(int nasid) } } - bte_res = xp_bte_copy(rp_pa, buf, buf_len, - (BTE_NOTIFY | BTE_WACQUIRE), NULL); - if (bte_res != BTE_SUCCESS) { - dev_dbg(xpc_part, "xp_bte_copy failed %i\n", bte_res); + ret = xp_remote_memcpy((void *)buf, (void *)rp_pa, buf_len); + if (ret != xpSuccess) { + dev_dbg(xpc_part, "xp_remote_memcpy failed %d\n", ret); status = SALRET_ERROR; break; } @@ -398,7 +397,7 @@ xpc_check_remote_hb(void) struct xpc_vars *remote_vars; struct xpc_partition *part; short partid; - bte_result_t bres; + enum xp_retval ret; remote_vars = (struct xpc_vars *)xpc_remote_copy_buffer; @@ -418,13 +417,11 @@ xpc_check_remote_hb(void) } /* pull the remote_hb cache line */ - bres = xp_bte_copy(part->remote_vars_pa, - (u64)remote_vars, - XPC_RP_VARS_SIZE, - (BTE_NOTIFY | BTE_WACQUIRE), NULL); - if (bres != BTE_SUCCESS) { - XPC_DEACTIVATE_PARTITION(part, - xpc_map_bte_errors(bres)); + ret = xp_remote_memcpy(remote_vars, + (void *)part->remote_vars_pa, + XPC_RP_VARS_SIZE); + if (ret != xpSuccess) { + XPC_DEACTIVATE_PARTITION(part, ret); continue; } @@ -457,7 +454,8 @@ static enum xp_retval xpc_get_remote_rp(int nasid, u64 *discovered_nasids, struct xpc_rsvd_page *remote_rp, u64 *remote_rp_pa) { - int bres, i; + int i; + enum xp_retval ret; /* get the reserved page's physical address */ @@ -466,11 +464,10 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, return xpNoRsvdPageAddr; /* pull over the reserved page header and part_nasids mask */ - bres = xp_bte_copy(*remote_rp_pa, (u64)remote_rp, - XPC_RP_HEADER_SIZE + xp_nasid_mask_bytes, - (BTE_NOTIFY | BTE_WACQUIRE), NULL); - if (bres != BTE_SUCCESS) - return xpc_map_bte_errors(bres); + ret = xp_remote_memcpy(remote_rp, (void *)*remote_rp_pa, + XPC_RP_HEADER_SIZE + xp_nasid_mask_bytes); + if (ret != xpSuccess) + return ret; if (discovered_nasids != NULL) { u64 *remote_part_nasids = XPC_RP_PART_NASIDS(remote_rp); @@ -504,16 +501,16 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, static enum xp_retval xpc_get_remote_vars(u64 remote_vars_pa, struct xpc_vars *remote_vars) { - int bres; + enum xp_retval ret; if (remote_vars_pa == 0) return xpVarsNotSet; /* pull over the cross partition variables */ - bres = xp_bte_copy(remote_vars_pa, (u64)remote_vars, XPC_RP_VARS_SIZE, - (BTE_NOTIFY | BTE_WACQUIRE), NULL); - if (bres != BTE_SUCCESS) - return xpc_map_bte_errors(bres); + ret = xp_remote_memcpy(remote_vars, (void *)remote_vars_pa, + XPC_RP_VARS_SIZE); + if (ret != xpSuccess) + return ret; if (XPC_VERSION_MAJOR(remote_vars->version) != XPC_VERSION_MAJOR(XPC_V_VERSION)) { @@ -1148,7 +1145,6 @@ xpc_initiate_partid_to_nasids(short partid, void *nasid_mask) { struct xpc_partition *part; u64 part_nasid_pa; - int bte_res; part = &xpc_partitions[partid]; if (part->remote_rp_pa == 0) @@ -1158,9 +1154,6 @@ xpc_initiate_partid_to_nasids(short partid, void *nasid_mask) part_nasid_pa = (u64)XPC_RP_PART_NASIDS(part->remote_rp_pa); - bte_res = xp_bte_copy(part_nasid_pa, (u64)nasid_mask, - xp_nasid_mask_bytes, (BTE_NOTIFY | BTE_WACQUIRE), - NULL); - - return xpc_map_bte_errors(bte_res); + return xp_remote_memcpy(nasid_mask, (void *)part_nasid_pa, + xp_nasid_mask_bytes); } diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index cc252f201b2..9c540eb1847 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -169,7 +168,7 @@ static void xpnet_receive(short partid, int channel, struct xpnet_message *msg) { struct sk_buff *skb; - bte_result_t bret; + enum xp_retval ret; struct xpnet_dev_private *priv = (struct xpnet_dev_private *)xpnet_device->priv; @@ -201,7 +200,7 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) /* * The allocated skb has some reserved space. - * In order to use bte_copy, we need to get the + * In order to use xp_remote_memcpy(), we need to get the * skb->data pointer moved forward. */ skb_reserve(skb, (L1_CACHE_BYTES - ((u64)skb->data & @@ -227,25 +226,24 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) (size_t)msg->embedded_bytes); } else { dev_dbg(xpnet, "transferring buffer to the skb->data area;\n\t" - "bte_copy(0x%p, 0x%p, %hu)\n", (void *)msg->buf_pa, - (void *)__pa((u64)skb->data & ~(L1_CACHE_BYTES - 1)), - msg->size); + "xp_remote_memcpy(0x%p, 0x%p, %hu)\n", (void *) + ((u64)skb->data & ~(L1_CACHE_BYTES - 1)), + (void *)msg->buf_pa, msg->size); - bret = bte_copy(msg->buf_pa, - __pa((u64)skb->data & ~(L1_CACHE_BYTES - 1)), - msg->size, (BTE_NOTIFY | BTE_WACQUIRE), NULL); + ret = xp_remote_memcpy((void *)((u64)skb->data & + ~(L1_CACHE_BYTES - 1)), + (void *)msg->buf_pa, msg->size); - if (bret != BTE_SUCCESS) { + if (ret != xpSuccess) { /* * >>> Need better way of cleaning skb. Currently skb * >>> appears in_use and we can't just call * >>> dev_kfree_skb. */ - dev_err(xpnet, "bte_copy(0x%p, 0x%p, 0x%hx) returned " - "error=0x%x\n", (void *)msg->buf_pa, - (void *)__pa((u64)skb->data & - ~(L1_CACHE_BYTES - 1)), - msg->size, bret); + dev_err(xpnet, "xp_remote_memcpy(0x%p, 0x%p, 0x%hx) " + "returned error=0x%x\n", (void *) + ((u64)skb->data & ~(L1_CACHE_BYTES - 1)), + (void *)msg->buf_pa, msg->size, ret); xpc_received(partid, channel, (void *)msg); -- cgit v1.2.3 From 94bd2708d4a95d7da5a1c7c28a063eccd127fb69 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:05 -0700 Subject: sgi-xp: prepare xpc_rsvd_page to work on either sn2 or uv hardware Prepare XPC's reserved page header to work for either sn2 or uv. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/Makefile | 3 +- drivers/misc/sgi-xp/xp.h | 5 +- drivers/misc/sgi-xp/xpc.h | 57 +++++++++----- drivers/misc/sgi-xp/xpc_main.c | 27 ++++++- drivers/misc/sgi-xp/xpc_partition.c | 149 +++++++++++------------------------- drivers/misc/sgi-xp/xpc_sn2.c | 111 +++++++++++++++++++++++++++ drivers/misc/sgi-xp/xpc_uv.c | 48 ++++++++++++ 7 files changed, 267 insertions(+), 133 deletions(-) create mode 100644 drivers/misc/sgi-xp/xpc_sn2.c create mode 100644 drivers/misc/sgi-xp/xpc_uv.c (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/Makefile b/drivers/misc/sgi-xp/Makefile index b50f2921781..b3eeff31ebf 100644 --- a/drivers/misc/sgi-xp/Makefile +++ b/drivers/misc/sgi-xp/Makefile @@ -7,6 +7,7 @@ xp-y := xp_main.o xp_uv.o xp-$(CONFIG_IA64) += xp_sn2.o xp_nofault.o obj-$(CONFIG_SGI_XP) += xpc.o -xpc-y := xpc_main.o xpc_channel.o xpc_partition.o +xpc-y := xpc_main.o xpc_uv.o xpc_channel.o xpc_partition.o +xpc-$(CONFIG_IA64) += xpc_sn2.o obj-$(CONFIG_SGI_XP) += xpnet.o diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index c42196a1a6b..0f75592896d 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -220,9 +220,10 @@ enum xp_retval { xpBteCopyError, /* 52: bte_copy() returned error */ xpSalError, /* 53: sn SAL error */ + xpRsvdPageNotSet, /* 54: the reserved page is not set up */ - xpUnsupported, /* 54: unsupported functionality or resource */ - xpUnknownReason /* 55: unknown reason - must be last in enum */ + xpUnsupported, /* 55: unsupported functionality or resource */ + xpUnknownReason /* 56: unknown reason - must be last in enum */ }; /* diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 60388bed770..94b52bb8151 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -71,11 +71,11 @@ * * reserved page header * - * The first cacheline of the reserved page contains the header - * (struct xpc_rsvd_page). Before SAL initialization has completed, + * The first two 64-byte cachelines of the reserved page contain the + * header (struct xpc_rsvd_page). Before SAL initialization has completed, * SAL has set up the following fields of the reserved page header: - * SAL_signature, SAL_version, partid, and nasids_size. The other - * fields are set up by XPC. (xpc_rsvd_page points to the local + * SAL_signature, SAL_version, SAL_partid, and SAL_nasids_size. The + * other fields are set up by XPC. (xpc_rsvd_page points to the local * partition's reserved page.) * * part_nasids mask @@ -89,11 +89,11 @@ * nasids. The part_nasids mask is located starting at the first cacheline * following the reserved page header. The mach_nasids mask follows right * after the part_nasids mask. The size in bytes of each mask is reflected - * by the reserved page header field 'nasids_size'. (Local partition's + * by the reserved page header field 'SAL_nasids_size'. (Local partition's * mask pointers are xpc_part_nasids and xpc_mach_nasids.) * - * vars - * vars part + * vars (ia64-sn2 only) + * vars part (ia64-sn2 only) * * Immediately following the mach_nasids mask are the XPC variables * required by other partitions. First are those that are generic to all @@ -101,25 +101,31 @@ * which are partition specific (vars part). These are setup by XPC. * (Local partition's vars pointers are xpc_vars and xpc_vars_part.) * - * Note: Until vars_pa is set, the partition XPC code has not been initialized. + * Note: Until 'stamp' is set non-zero, the partition XPC code has not been + * initialized. */ struct xpc_rsvd_page { u64 SAL_signature; /* SAL: unique signature */ u64 SAL_version; /* SAL: version */ - u8 partid; /* SAL: partition ID */ + short SAL_partid; /* SAL: partition ID */ + short max_npartitions; /* value of XPC_MAX_PARTITIONS */ u8 version; - u8 pad1[6]; /* align to next u64 in cacheline */ - u64 vars_pa; /* physical address of struct xpc_vars */ + u8 pad1[3]; /* align to next u64 in 1st 64-byte cacheline */ + union { + u64 vars_pa; /* physical address of struct xpc_vars */ + u64 activate_mq_gpa; /* global phys address of activate_mq */ + } sn; struct timespec stamp; /* time when reserved page was setup by XPC */ - u64 pad2[9]; /* align to last u64 in cacheline */ - u64 nasids_size; /* SAL: size of each nasid mask in bytes */ + u64 pad2[9]; /* align to last u64 in 2nd 64-byte cacheline */ + u64 SAL_nasids_size; /* SAL: size of each nasid mask in bytes */ }; -#define XPC_RP_VERSION _XPC_VERSION(1, 1) /* version 1.1 of the reserved page */ +#define XPC_RP_VERSION _XPC_VERSION(2, 0) /* version 2.0 of the reserved page */ #define XPC_SUPPORTS_RP_STAMP(_version) \ (_version >= _XPC_VERSION(1, 1)) +#define ZERO_STAMP ((struct timespec){0, 0}) /* * compare stamps - the return value is: * @@ -218,10 +224,10 @@ xpc_disallow_hb(short partid, struct xpc_vars *vars) * * An array of these structures, one per partition, will be defined. As a * partition becomes active XPC will copy the array entry corresponding to - * itself from that partition. It is desirable that the size of this - * structure evenly divide into a cacheline, such that none of the entries - * in this array crosses a cacheline boundary. As it is now, each entry - * occupies half a cacheline. + * itself from that partition. It is desirable that the size of this structure + * evenly divides into a 128-byte cacheline, such that none of the entries in + * this array crosses a 128-byte cacheline boundary. As it is now, each entry + * occupies a 64-byte cacheline. */ struct xpc_vars_part { u64 magic; @@ -632,16 +638,25 @@ extern void xpc_activate_kthreads(struct xpc_channel *, int); extern void xpc_create_kthreads(struct xpc_channel *, int, int); extern void xpc_disconnect_wait(int); +extern enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *); + +/* found in xpc_sn2.c */ +extern void xpc_init_sn2(void); +extern struct xpc_vars *xpc_vars; /*>>> eliminate from here */ +extern struct xpc_vars_part *xpc_vars_part; /*>>> eliminate from here */ + +/* found in xpc_uv.c */ +extern void xpc_init_uv(void); + /* found in xpc_partition.c */ extern int xpc_exiting; -extern struct xpc_vars *xpc_vars; +extern int xp_nasid_mask_words; extern struct xpc_rsvd_page *xpc_rsvd_page; -extern struct xpc_vars_part *xpc_vars_part; extern struct xpc_partition *xpc_partitions; extern char *xpc_remote_copy_buffer; extern void *xpc_remote_copy_buffer_base; extern void *xpc_kmalloc_cacheline_aligned(size_t, gfp_t, void **); -extern struct xpc_rsvd_page *xpc_rsvd_page_init(void); +extern struct xpc_rsvd_page *xpc_setup_rsvd_page(void); extern void xpc_allow_IPI_ops(void); extern void xpc_restrict_IPI_ops(void); extern int xpc_identify_act_IRQ_sender(void); diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index a05c7c7da22..2180f1f7e08 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -175,6 +175,8 @@ static struct notifier_block xpc_die_notifier = { .notifier_call = xpc_system_die, }; +enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *rp); + /* * Timer function to enforce the timelimit on the partition disengage request. */ @@ -949,7 +951,7 @@ xpc_do_exit(enum xp_retval reason) DBUG_ON(xpc_partition_engaged(-1UL)); /* indicate to others that our reserved page is uninitialized */ - xpc_rsvd_page->vars_pa = 0; + xpc_rsvd_page->stamp = ZERO_STAMP; /* now it's time to eliminate our heartbeat */ del_timer_sync(&xpc_hb_timer); @@ -1128,8 +1130,24 @@ xpc_init(void) struct task_struct *kthread; size_t buf_size; - if (!ia64_platform_is("sn2")) + if (is_shub()) { + /* + * The ia64-sn2 architecture supports at most 64 partitions. + * And the inability to unregister remote AMOs restricts us + * further to only support exactly 64 partitions on this + * architecture, no less. + */ + if (xp_max_npartitions != 64) + return -EINVAL; + + xpc_init_sn2(); + + } else if (is_uv()) { + xpc_init_uv(); + + } else { return -ENODEV; + } snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part"); snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan"); @@ -1214,7 +1232,7 @@ xpc_init(void) * other partitions to discover we are alive and establish initial * communications. */ - xpc_rsvd_page = xpc_rsvd_page_init(); + xpc_rsvd_page = xpc_setup_rsvd_page(); if (xpc_rsvd_page == NULL) { dev_err(xpc_part, "can't setup our reserved page\n"); ret = -EBUSY; @@ -1273,7 +1291,8 @@ xpc_init(void) /* initialization was not successful */ out_4: /* indicate to others that our reserved page is uninitialized */ - xpc_rsvd_page->vars_pa = 0; + xpc_rsvd_page->stamp = ZERO_STAMP; + del_timer_sync(&xpc_hb_timer); (void)unregister_die_notifier(&xpc_die_notifier); (void)unregister_reboot_notifier(&xpc_reboot_notifier); diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 6c82f205097..1db84cb4914 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -44,11 +43,10 @@ u64 xpc_prot_vec[MAX_NUMNODES]; struct xpc_rsvd_page *xpc_rsvd_page; static u64 *xpc_part_nasids; static u64 *xpc_mach_nasids; -struct xpc_vars *xpc_vars; -struct xpc_vars_part *xpc_vars_part; -static int xp_nasid_mask_bytes; /* actual size in bytes of nasid mask */ -static int xp_nasid_mask_words; /* actual size in words of nasid mask */ +/* >>> next two variables should be 'xpc_' if they remain here */ +static int xp_sizeof_nasid_mask; /* actual size in bytes of nasid mask */ +int xp_nasid_mask_words; /* actual size in words of nasid mask */ struct xpc_partition *xpc_partitions; @@ -150,12 +148,10 @@ xpc_get_rsvd_page_pa(int nasid) * communications. */ struct xpc_rsvd_page * -xpc_rsvd_page_init(void) +xpc_setup_rsvd_page(void) { struct xpc_rsvd_page *rp; - AMO_t *amos_page; - u64 rp_pa, nasid_array = 0; - int i, ret; + u64 rp_pa; /* get the local reserved page's address */ @@ -168,110 +164,44 @@ xpc_rsvd_page_init(void) } rp = (struct xpc_rsvd_page *)__va(rp_pa); - if (rp->partid != sn_partition_id) { - dev_err(xpc_part, "the reserved page's partid of %d should be " - "%d\n", rp->partid, sn_partition_id); + if (rp->SAL_version < 3) { + /* SAL_versions < 3 had a SAL_partid defined as a u8 */ + rp->SAL_partid &= 0xff; + } + BUG_ON(rp->SAL_partid != sn_partition_id); + + if (rp->SAL_partid < 0 || rp->SAL_partid >= xp_max_npartitions) { + dev_err(xpc_part, "the reserved page's partid of %d is outside " + "supported range (< 0 || >= %d)\n", rp->SAL_partid, + xp_max_npartitions); return NULL; } rp->version = XPC_RP_VERSION; + rp->max_npartitions = xp_max_npartitions; /* establish the actual sizes of the nasid masks */ if (rp->SAL_version == 1) { /* SAL_version 1 didn't set the nasids_size field */ - rp->nasids_size = 128; + rp->SAL_nasids_size = 128; } - xp_nasid_mask_bytes = rp->nasids_size; - xp_nasid_mask_words = xp_nasid_mask_bytes / 8; + xp_sizeof_nasid_mask = rp->SAL_nasids_size; + xp_nasid_mask_words = DIV_ROUND_UP(xp_sizeof_nasid_mask, + BYTES_PER_WORD); /* setup the pointers to the various items in the reserved page */ xpc_part_nasids = XPC_RP_PART_NASIDS(rp); xpc_mach_nasids = XPC_RP_MACH_NASIDS(rp); - xpc_vars = XPC_RP_VARS(rp); - xpc_vars_part = XPC_RP_VARS_PART(rp); - /* - * Before clearing xpc_vars, see if a page of AMOs had been previously - * allocated. If not we'll need to allocate one and set permissions - * so that cross-partition AMOs are allowed. - * - * The allocated AMO page needs MCA reporting to remain disabled after - * XPC has unloaded. To make this work, we keep a copy of the pointer - * to this page (i.e., amos_page) in the struct xpc_vars structure, - * which is pointed to by the reserved page, and re-use that saved copy - * on subsequent loads of XPC. This AMO page is never freed, and its - * memory protections are never restricted. - */ - amos_page = xpc_vars->amos_page; - if (amos_page == NULL) { - amos_page = (AMO_t *)TO_AMO(uncached_alloc_page(0, 1)); - if (amos_page == NULL) { - dev_err(xpc_part, "can't allocate page of AMOs\n"); - return NULL; - } - - /* - * Open up AMO-R/W to cpu. This is done for Shub 1.1 systems - * when xpc_allow_IPI_ops() is called via xpc_hb_init(). - */ - if (!enable_shub_wars_1_1()) { - ret = sn_change_memprotect(ia64_tpa((u64)amos_page), - PAGE_SIZE, - SN_MEMPROT_ACCESS_CLASS_1, - &nasid_array); - if (ret != 0) { - dev_err(xpc_part, "can't change memory " - "protections\n"); - uncached_free_page(__IA64_UNCACHED_OFFSET | - TO_PHYS((u64)amos_page), 1); - return NULL; - } - } - } else if (!IS_AMO_ADDRESS((u64)amos_page)) { - /* - * EFI's XPBOOT can also set amos_page in the reserved page, - * but it happens to leave it as an uncached physical address - * and we need it to be an uncached virtual, so we'll have to - * convert it. - */ - if (!IS_AMO_PHYS_ADDRESS((u64)amos_page)) { - dev_err(xpc_part, "previously used amos_page address " - "is bad = 0x%p\n", (void *)amos_page); - return NULL; - } - amos_page = (AMO_t *)TO_AMO((u64)amos_page); - } - - /* clear xpc_vars */ - memset(xpc_vars, 0, sizeof(struct xpc_vars)); - - xpc_vars->version = XPC_V_VERSION; - xpc_vars->act_nasid = cpuid_to_nasid(0); - xpc_vars->act_phys_cpuid = cpu_physical_id(0); - xpc_vars->vars_part_pa = __pa(xpc_vars_part); - xpc_vars->amos_page_pa = ia64_tpa((u64)amos_page); - xpc_vars->amos_page = amos_page; /* save for next load of XPC */ - - /* clear xpc_vars_part */ - memset((u64 *)xpc_vars_part, 0, sizeof(struct xpc_vars_part) * - xp_max_npartitions); - - /* initialize the activate IRQ related AMO variables */ - for (i = 0; i < xp_nasid_mask_words; i++) - (void)xpc_IPI_init(XPC_ACTIVATE_IRQ_AMOS + i); - - /* initialize the engaged remote partitions related AMO variables */ - (void)xpc_IPI_init(XPC_ENGAGED_PARTITIONS_AMO); - (void)xpc_IPI_init(XPC_DISENGAGE_REQUEST_AMO); - - /* timestamp of when reserved page was setup by XPC */ - rp->stamp = CURRENT_TIME; + if (xpc_rsvd_page_init(rp) != xpSuccess) + return NULL; /* + * Set timestamp of when reserved page was setup by XPC. * This signifies to the remote partition that our reserved * page is initialized. */ - rp->vars_pa = __pa(xpc_vars); + rp->stamp = CURRENT_TIME; return rp; } @@ -465,7 +395,7 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, /* pull over the reserved page header and part_nasids mask */ ret = xp_remote_memcpy(remote_rp, (void *)*remote_rp_pa, - XPC_RP_HEADER_SIZE + xp_nasid_mask_bytes); + XPC_RP_HEADER_SIZE + xp_sizeof_nasid_mask); if (ret != xpSuccess) return ret; @@ -476,19 +406,28 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, discovered_nasids[i] |= remote_part_nasids[i]; } - /* check that the partid is for another partition */ + /* check that the partid is valid and is for another partition */ - if (remote_rp->partid < 0 || remote_rp->partid >= xp_max_npartitions) + if (remote_rp->SAL_partid < 0 || + remote_rp->SAL_partid >= xp_max_npartitions) { return xpInvalidPartid; + } - if (remote_rp->partid == sn_partition_id) + if (remote_rp->SAL_partid == sn_partition_id) return xpLocalPartid; + /* see if the rest of the reserved page has been set up by XPC */ + if (timespec_equal(&remote_rp->stamp, &ZERO_STAMP)) + return xpRsvdPageNotSet; + if (XPC_VERSION_MAJOR(remote_rp->version) != XPC_VERSION_MAJOR(XPC_RP_VERSION)) { return xpBadVersion; } + if (remote_rp->max_npartitions <= sn_partition_id) + return xpInvalidPartid; + return xpSuccess; } @@ -592,7 +531,7 @@ xpc_identify_act_IRQ_req(int nasid) int remote_rp_version; int reactivate = 0; int stamp_diff; - struct timespec remote_rp_stamp = { 0, 0 }; + struct timespec remote_rp_stamp = { 0, 0 }; /*>>> ZERO_STAMP */ short partid; struct xpc_partition *part; enum xp_retval ret; @@ -608,12 +547,12 @@ xpc_identify_act_IRQ_req(int nasid) return; } - remote_vars_pa = remote_rp->vars_pa; + remote_vars_pa = remote_rp->sn.vars_pa; remote_rp_version = remote_rp->version; if (XPC_SUPPORTS_RP_STAMP(remote_rp_version)) remote_rp_stamp = remote_rp->stamp; - partid = remote_rp->partid; + partid = remote_rp->SAL_partid; part = &xpc_partitions[partid]; /* pull over the cross partition variables */ @@ -977,7 +916,7 @@ xpc_discovery(void) enum xp_retval ret; remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE + - xp_nasid_mask_bytes, + xp_sizeof_nasid_mask, GFP_KERNEL, &remote_rp_base); if (remote_rp == NULL) return; @@ -1063,9 +1002,9 @@ xpc_discovery(void) continue; } - remote_vars_pa = remote_rp->vars_pa; + remote_vars_pa = remote_rp->sn.vars_pa; - partid = remote_rp->partid; + partid = remote_rp->SAL_partid; part = &xpc_partitions[partid]; /* pull over the cross partition variables */ @@ -1155,5 +1094,5 @@ xpc_initiate_partid_to_nasids(short partid, void *nasid_mask) part_nasid_pa = (u64)XPC_RP_PART_NASIDS(part->remote_rp_pa); return xp_remote_memcpy(nasid_mask, (void *)part_nasid_pa, - xp_nasid_mask_bytes); + xp_sizeof_nasid_mask); } diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c new file mode 100644 index 00000000000..5a37348715c --- /dev/null +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -0,0 +1,111 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + */ + +/* + * Cross Partition Communication (XPC) sn2-based functions. + * + * Architecture specific implementation of common functions. + * + */ + +#include +#include +#include +#include "xpc.h" + +struct xpc_vars *xpc_vars; +struct xpc_vars_part *xpc_vars_part; + +static enum xp_retval +xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) +{ + AMO_t *amos_page; + u64 nasid_array = 0; + int i; + int ret; + + xpc_vars = XPC_RP_VARS(rp); + + rp->sn.vars_pa = __pa(xpc_vars); + + xpc_vars_part = XPC_RP_VARS_PART(rp); + + /* + * Before clearing xpc_vars, see if a page of AMOs had been previously + * allocated. If not we'll need to allocate one and set permissions + * so that cross-partition AMOs are allowed. + * + * The allocated AMO page needs MCA reporting to remain disabled after + * XPC has unloaded. To make this work, we keep a copy of the pointer + * to this page (i.e., amos_page) in the struct xpc_vars structure, + * which is pointed to by the reserved page, and re-use that saved copy + * on subsequent loads of XPC. This AMO page is never freed, and its + * memory protections are never restricted. + */ + amos_page = xpc_vars->amos_page; + if (amos_page == NULL) { + amos_page = (AMO_t *)TO_AMO(uncached_alloc_page(0, 1)); + if (amos_page == NULL) { + dev_err(xpc_part, "can't allocate page of AMOs\n"); + return xpNoMemory; + } + + /* + * Open up AMO-R/W to cpu. This is done for Shub 1.1 systems + * when xpc_allow_IPI_ops() is called via xpc_hb_init(). + */ + if (!enable_shub_wars_1_1()) { + ret = sn_change_memprotect(ia64_tpa((u64)amos_page), + PAGE_SIZE, + SN_MEMPROT_ACCESS_CLASS_1, + &nasid_array); + if (ret != 0) { + dev_err(xpc_part, "can't change memory " + "protections\n"); + uncached_free_page(__IA64_UNCACHED_OFFSET | + TO_PHYS((u64)amos_page), 1); + return xpSalError; + } + } + } + + /* clear xpc_vars */ + memset(xpc_vars, 0, sizeof(struct xpc_vars)); + + xpc_vars->version = XPC_V_VERSION; + xpc_vars->act_nasid = cpuid_to_nasid(0); + xpc_vars->act_phys_cpuid = cpu_physical_id(0); + xpc_vars->vars_part_pa = __pa(xpc_vars_part); + xpc_vars->amos_page_pa = ia64_tpa((u64)amos_page); + xpc_vars->amos_page = amos_page; /* save for next load of XPC */ + + /* clear xpc_vars_part */ + memset((u64 *)xpc_vars_part, 0, sizeof(struct xpc_vars_part) * + xp_max_npartitions); + + /* initialize the activate IRQ related AMO variables */ + for (i = 0; i < xp_nasid_mask_words; i++) + (void)xpc_IPI_init(XPC_ACTIVATE_IRQ_AMOS + i); + + /* initialize the engaged remote partitions related AMO variables */ + (void)xpc_IPI_init(XPC_ENGAGED_PARTITIONS_AMO); + (void)xpc_IPI_init(XPC_DISENGAGE_REQUEST_AMO); + + return xpSuccess; +} + +void +xpc_init_sn2(void) +{ + xpc_rsvd_page_init = xpc_rsvd_page_init_sn2; +} + +void +xpc_exit_sn2(void) +{ +} diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c new file mode 100644 index 00000000000..8327cd4017e --- /dev/null +++ b/drivers/misc/sgi-xp/xpc_uv.c @@ -0,0 +1,48 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + */ + +/* + * Cross Partition Communication (XPC) uv-based functions. + * + * Architecture specific implementation of common functions. + * + */ + +#include + +/* >>> #include */ +/* >>> uv_gpa() is defined in */ +#define uv_gpa(_a) ((unsigned long)_a) + +/* >>> temporarily define next three items for xpc.h */ +#define SGI_XPC_ACTIVATE 23 +#define SGI_XPC_NOTIFY 24 +#define sn_send_IPI_phys(_a, _b, _c, _d) + +#include "xpc.h" + +static void *xpc_activate_mq; + +static enum xp_retval +xpc_rsvd_page_init_uv(struct xpc_rsvd_page *rp) +{ + /* >>> need to have established xpc_activate_mq earlier */ + rp->sn.activate_mq_gpa = uv_gpa(xpc_activate_mq); + return xpSuccess; +} + +void +xpc_init_uv(void) +{ + xpc_rsvd_page_init = xpc_rsvd_page_init_uv; +} + +void +xpc_exit_uv(void) +{ +} -- cgit v1.2.3 From e17d416b1bc947df68499863f13b401fb42b48f6 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:06 -0700 Subject: sgi-xp: isolate xpc_vars_part structure to sn2 only Isolate the xpc_vars_part structure of XPC's reserved page to sn2 only. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xpc.h | 26 +- drivers/misc/sgi-xp/xpc_channel.c | 538 +--------------------------------- drivers/misc/sgi-xp/xpc_main.c | 97 ++----- drivers/misc/sgi-xp/xpc_partition.c | 1 + drivers/misc/sgi-xp/xpc_sn2.c | 563 +++++++++++++++++++++++++++++++++++- drivers/misc/sgi-xp/xpc_uv.c | 48 +++ 6 files changed, 644 insertions(+), 629 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 94b52bb8151..e8c2a162960 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -227,9 +227,9 @@ xpc_disallow_hb(short partid, struct xpc_vars *vars) * itself from that partition. It is desirable that the size of this structure * evenly divides into a 128-byte cacheline, such that none of the entries in * this array crosses a 128-byte cacheline boundary. As it is now, each entry - * occupies a 64-byte cacheline. + * occupies 64-bytes. */ -struct xpc_vars_part { +struct xpc_vars_part_sn2 { u64 magic; u64 openclose_args_pa; /* physical address of open and close args */ @@ -265,8 +265,6 @@ struct xpc_vars_part { #define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + xp_nasid_mask_words) #define XPC_RP_VARS(_rp) ((struct xpc_vars *)(XPC_RP_MACH_NASIDS(_rp) + \ xp_nasid_mask_words)) -#define XPC_RP_VARS_PART(_rp) ((struct xpc_vars_part *) \ - ((u8 *)XPC_RP_VARS(_rp) + XPC_RP_VARS_SIZE)) /* * Functions registered by add_timer() or called by kernel_thread() only @@ -541,13 +539,6 @@ struct xpc_partition { wait_queue_head_t teardown_wq; /* kthread waiting to teardown infra */ atomic_t references; /* #of references to infrastructure */ - /* - * NONE OF THE PRECEDING FIELDS OF THIS STRUCTURE WILL BE CLEARED WHEN - * XPC SETS UP THE NECESSARY INFRASTRUCTURE TO SUPPORT CROSS PARTITION - * COMMUNICATION. ALL OF THE FOLLOWING FIELDS WILL BE CLEARED. (THE - * 'nchannels' FIELD MUST BE THE FIRST OF THE FIELDS TO BE CLEARED.) - */ - u8 nchannels; /* #of defined channels supported */ atomic_t nchannels_active; /* #of channels that are not DISCONNECTED */ atomic_t nchannels_engaged; /* #of channels engaged with remote part */ @@ -613,7 +604,7 @@ struct xpc_partition { * dropped IPIs. These occur whenever an IPI amo write doesn't complete until * after the IPI was received. */ -#define XPC_P_DROPPED_IPI_WAIT (0.25 * HZ) +#define XPC_P_DROPPED_IPI_WAIT_INTERVAL (0.25 * HZ) /* number of seconds to wait for other partitions to disengage */ #define XPC_DISENGAGE_REQUEST_DEFAULT_TIMELIMIT 90 @@ -637,13 +628,16 @@ extern void xpc_activate_partition(struct xpc_partition *); extern void xpc_activate_kthreads(struct xpc_channel *, int); extern void xpc_create_kthreads(struct xpc_channel *, int, int); extern void xpc_disconnect_wait(int); - extern enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *); +extern enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *); +extern u64 (*xpc_get_IPI_flags) (struct xpc_partition *); +extern struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *); +extern enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *); +extern void (*xpc_teardown_infrastructure) (struct xpc_partition *); /* found in xpc_sn2.c */ extern void xpc_init_sn2(void); extern struct xpc_vars *xpc_vars; /*>>> eliminate from here */ -extern struct xpc_vars_part *xpc_vars_part; /*>>> eliminate from here */ /* found in xpc_uv.c */ extern void xpc_init_uv(void); @@ -670,6 +664,7 @@ extern void xpc_deactivate_partition(const int, struct xpc_partition *, extern enum xp_retval xpc_initiate_partid_to_nasids(short, void *); /* found in xpc_channel.c */ +extern void *xpc_kzalloc_cacheline_aligned(size_t, gfp_t, void **); extern void xpc_initiate_connect(int); extern void xpc_initiate_disconnect(int); extern enum xp_retval xpc_initiate_allocate(short, int, u32, void **); @@ -677,8 +672,6 @@ extern enum xp_retval xpc_initiate_send(short, int, void *); extern enum xp_retval xpc_initiate_send_notify(short, int, void *, xpc_notify_func, void *); extern void xpc_initiate_received(short, int, void *); -extern enum xp_retval xpc_setup_infrastructure(struct xpc_partition *); -extern enum xp_retval xpc_pull_remote_vars_part(struct xpc_partition *); extern void xpc_process_channel_activity(struct xpc_partition *); extern void xpc_connected_callout(struct xpc_channel *); extern void xpc_deliver_msg(struct xpc_channel *); @@ -686,7 +679,6 @@ extern void xpc_disconnect_channel(const int, struct xpc_channel *, enum xp_retval, unsigned long *); extern void xpc_disconnect_callout(struct xpc_channel *, enum xp_retval); extern void xpc_partition_going_down(struct xpc_partition *, enum xp_retval); -extern void xpc_teardown_infrastructure(struct xpc_partition *); static inline void xpc_wakeup_channel_mgr(struct xpc_partition *part) diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index 9e79ad7eafe..8081e8155df 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -27,7 +27,7 @@ /* * Guarantee that the kzalloc'd memory is cacheline aligned. */ -static void * +void * xpc_kzalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) { /* see if kzalloc will give us cachline aligned memory by default */ @@ -48,382 +48,6 @@ xpc_kzalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) return (void *)L1_CACHE_ALIGN((u64)*base); } -/* - * Set up the initial values for the XPartition Communication channels. - */ -static void -xpc_initialize_channels(struct xpc_partition *part, short partid) -{ - int ch_number; - struct xpc_channel *ch; - - for (ch_number = 0; ch_number < part->nchannels; ch_number++) { - ch = &part->channels[ch_number]; - - ch->partid = partid; - ch->number = ch_number; - ch->flags = XPC_C_DISCONNECTED; - - ch->local_GP = &part->local_GPs[ch_number]; - ch->local_openclose_args = - &part->local_openclose_args[ch_number]; - - atomic_set(&ch->kthreads_assigned, 0); - atomic_set(&ch->kthreads_idle, 0); - atomic_set(&ch->kthreads_active, 0); - - atomic_set(&ch->references, 0); - atomic_set(&ch->n_to_notify, 0); - - spin_lock_init(&ch->lock); - mutex_init(&ch->msg_to_pull_mutex); - init_completion(&ch->wdisconnect_wait); - - atomic_set(&ch->n_on_msg_allocate_wq, 0); - init_waitqueue_head(&ch->msg_allocate_wq); - init_waitqueue_head(&ch->idle_wq); - } -} - -/* - * Setup the infrastructure necessary to support XPartition Communication - * between the specified remote partition and the local one. - */ -enum xp_retval -xpc_setup_infrastructure(struct xpc_partition *part) -{ - int ret, cpuid; - struct timer_list *timer; - short partid = XPC_PARTID(part); - - /* - * Zero out MOST of the entry for this partition. Only the fields - * starting with `nchannels' will be zeroed. The preceding fields must - * remain `viable' across partition ups and downs, since they may be - * referenced during this memset() operation. - */ - memset(&part->nchannels, 0, sizeof(struct xpc_partition) - - offsetof(struct xpc_partition, nchannels)); - - /* - * Allocate all of the channel structures as a contiguous chunk of - * memory. - */ - part->channels = kzalloc(sizeof(struct xpc_channel) * XPC_MAX_NCHANNELS, - GFP_KERNEL); - if (part->channels == NULL) { - dev_err(xpc_chan, "can't get memory for channels\n"); - return xpNoMemory; - } - - part->nchannels = XPC_MAX_NCHANNELS; - - /* allocate all the required GET/PUT values */ - - part->local_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, - GFP_KERNEL, - &part->local_GPs_base); - if (part->local_GPs == NULL) { - kfree(part->channels); - part->channels = NULL; - dev_err(xpc_chan, "can't get memory for local get/put " - "values\n"); - return xpNoMemory; - } - - part->remote_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, - GFP_KERNEL, - &part-> - remote_GPs_base); - if (part->remote_GPs == NULL) { - dev_err(xpc_chan, "can't get memory for remote get/put " - "values\n"); - kfree(part->local_GPs_base); - part->local_GPs = NULL; - kfree(part->channels); - part->channels = NULL; - return xpNoMemory; - } - - /* allocate all the required open and close args */ - - part->local_openclose_args = - xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL, - &part->local_openclose_args_base); - if (part->local_openclose_args == NULL) { - dev_err(xpc_chan, "can't get memory for local connect args\n"); - kfree(part->remote_GPs_base); - part->remote_GPs = NULL; - kfree(part->local_GPs_base); - part->local_GPs = NULL; - kfree(part->channels); - part->channels = NULL; - return xpNoMemory; - } - - part->remote_openclose_args = - xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL, - &part->remote_openclose_args_base); - if (part->remote_openclose_args == NULL) { - dev_err(xpc_chan, "can't get memory for remote connect args\n"); - kfree(part->local_openclose_args_base); - part->local_openclose_args = NULL; - kfree(part->remote_GPs_base); - part->remote_GPs = NULL; - kfree(part->local_GPs_base); - part->local_GPs = NULL; - kfree(part->channels); - part->channels = NULL; - return xpNoMemory; - } - - xpc_initialize_channels(part, partid); - - atomic_set(&part->nchannels_active, 0); - atomic_set(&part->nchannels_engaged, 0); - - /* local_IPI_amo were set to 0 by an earlier memset() */ - - /* Initialize this partitions AMO_t structure */ - part->local_IPI_amo_va = xpc_IPI_init(partid); - - spin_lock_init(&part->IPI_lock); - - atomic_set(&part->channel_mgr_requests, 1); - init_waitqueue_head(&part->channel_mgr_wq); - - sprintf(part->IPI_owner, "xpc%02d", partid); - ret = request_irq(SGI_XPC_NOTIFY, xpc_notify_IRQ_handler, IRQF_SHARED, - part->IPI_owner, (void *)(u64)partid); - if (ret != 0) { - dev_err(xpc_chan, "can't register NOTIFY IRQ handler, " - "errno=%d\n", -ret); - kfree(part->remote_openclose_args_base); - part->remote_openclose_args = NULL; - kfree(part->local_openclose_args_base); - part->local_openclose_args = NULL; - kfree(part->remote_GPs_base); - part->remote_GPs = NULL; - kfree(part->local_GPs_base); - part->local_GPs = NULL; - kfree(part->channels); - part->channels = NULL; - return xpLackOfResources; - } - - /* Setup a timer to check for dropped IPIs */ - timer = &part->dropped_IPI_timer; - init_timer(timer); - timer->function = (void (*)(unsigned long))xpc_dropped_IPI_check; - timer->data = (unsigned long)part; - timer->expires = jiffies + XPC_P_DROPPED_IPI_WAIT; - add_timer(timer); - - /* - * With the setting of the partition setup_state to XPC_P_SETUP, we're - * declaring that this partition is ready to go. - */ - part->setup_state = XPC_P_SETUP; - - /* - * Setup the per partition specific variables required by the - * remote partition to establish channel connections with us. - * - * The setting of the magic # indicates that these per partition - * specific variables are ready to be used. - */ - xpc_vars_part[partid].GPs_pa = __pa(part->local_GPs); - xpc_vars_part[partid].openclose_args_pa = - __pa(part->local_openclose_args); - xpc_vars_part[partid].IPI_amo_pa = __pa(part->local_IPI_amo_va); - cpuid = raw_smp_processor_id(); /* any CPU in this partition will do */ - xpc_vars_part[partid].IPI_nasid = cpuid_to_nasid(cpuid); - xpc_vars_part[partid].IPI_phys_cpuid = cpu_physical_id(cpuid); - xpc_vars_part[partid].nchannels = part->nchannels; - xpc_vars_part[partid].magic = XPC_VP_MAGIC1; - - return xpSuccess; -} - -/* - * Create a wrapper that hides the underlying mechanism for pulling a cacheline - * (or multiple cachelines) from a remote partition. - * - * src must be a cacheline aligned physical address on the remote partition. - * dst must be a cacheline aligned virtual address on this partition. - * cnt must be cacheline sized - */ -static enum xp_retval -xpc_pull_remote_cachelines(struct xpc_partition *part, void *dst, - const void *src, size_t cnt) -{ - enum xp_retval ret; - - DBUG_ON((u64)src != L1_CACHE_ALIGN((u64)src)); - DBUG_ON((u64)dst != L1_CACHE_ALIGN((u64)dst)); - DBUG_ON(cnt != L1_CACHE_ALIGN(cnt)); - - if (part->act_state == XPC_P_DEACTIVATING) - return part->reason; - - ret = xp_remote_memcpy(dst, src, cnt); - if (ret != xpSuccess) { - dev_dbg(xpc_chan, "xp_remote_memcpy() from partition %d failed," - " ret=%d\n", XPC_PARTID(part), ret); - } - return ret; -} - -/* - * Pull the remote per partition specific variables from the specified - * partition. - */ -enum xp_retval -xpc_pull_remote_vars_part(struct xpc_partition *part) -{ - u8 buffer[L1_CACHE_BYTES * 2]; - struct xpc_vars_part *pulled_entry_cacheline = - (struct xpc_vars_part *)L1_CACHE_ALIGN((u64)buffer); - struct xpc_vars_part *pulled_entry; - u64 remote_entry_cacheline_pa, remote_entry_pa; - short partid = XPC_PARTID(part); - enum xp_retval ret; - - /* pull the cacheline that contains the variables we're interested in */ - - DBUG_ON(part->remote_vars_part_pa != - L1_CACHE_ALIGN(part->remote_vars_part_pa)); - DBUG_ON(sizeof(struct xpc_vars_part) != L1_CACHE_BYTES / 2); - - remote_entry_pa = part->remote_vars_part_pa + - sn_partition_id * sizeof(struct xpc_vars_part); - - remote_entry_cacheline_pa = (remote_entry_pa & ~(L1_CACHE_BYTES - 1)); - - pulled_entry = (struct xpc_vars_part *)((u64)pulled_entry_cacheline + - (remote_entry_pa & - (L1_CACHE_BYTES - 1))); - - ret = xpc_pull_remote_cachelines(part, pulled_entry_cacheline, - (void *)remote_entry_cacheline_pa, - L1_CACHE_BYTES); - if (ret != xpSuccess) { - dev_dbg(xpc_chan, "failed to pull XPC vars_part from " - "partition %d, ret=%d\n", partid, ret); - return ret; - } - - /* see if they've been set up yet */ - - if (pulled_entry->magic != XPC_VP_MAGIC1 && - pulled_entry->magic != XPC_VP_MAGIC2) { - - if (pulled_entry->magic != 0) { - dev_dbg(xpc_chan, "partition %d's XPC vars_part for " - "partition %d has bad magic value (=0x%lx)\n", - partid, sn_partition_id, pulled_entry->magic); - return xpBadMagic; - } - - /* they've not been initialized yet */ - return xpRetry; - } - - if (xpc_vars_part[partid].magic == XPC_VP_MAGIC1) { - - /* validate the variables */ - - if (pulled_entry->GPs_pa == 0 || - pulled_entry->openclose_args_pa == 0 || - pulled_entry->IPI_amo_pa == 0) { - - dev_err(xpc_chan, "partition %d's XPC vars_part for " - "partition %d are not valid\n", partid, - sn_partition_id); - return xpInvalidAddress; - } - - /* the variables we imported look to be valid */ - - part->remote_GPs_pa = pulled_entry->GPs_pa; - part->remote_openclose_args_pa = - pulled_entry->openclose_args_pa; - part->remote_IPI_amo_va = - (AMO_t *)__va(pulled_entry->IPI_amo_pa); - part->remote_IPI_nasid = pulled_entry->IPI_nasid; - part->remote_IPI_phys_cpuid = pulled_entry->IPI_phys_cpuid; - - if (part->nchannels > pulled_entry->nchannels) - part->nchannels = pulled_entry->nchannels; - - /* let the other side know that we've pulled their variables */ - - xpc_vars_part[partid].magic = XPC_VP_MAGIC2; - } - - if (pulled_entry->magic == XPC_VP_MAGIC1) - return xpRetry; - - return xpSuccess; -} - -/* - * Get the IPI flags and pull the openclose args and/or remote GPs as needed. - */ -static u64 -xpc_get_IPI_flags(struct xpc_partition *part) -{ - unsigned long irq_flags; - u64 IPI_amo; - enum xp_retval ret; - - /* - * See if there are any IPI flags to be handled. - */ - - spin_lock_irqsave(&part->IPI_lock, irq_flags); - IPI_amo = part->local_IPI_amo; - if (IPI_amo != 0) - part->local_IPI_amo = 0; - - spin_unlock_irqrestore(&part->IPI_lock, irq_flags); - - if (XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(IPI_amo)) { - ret = xpc_pull_remote_cachelines(part, - part->remote_openclose_args, - (void *)part-> - remote_openclose_args_pa, - XPC_OPENCLOSE_ARGS_SIZE); - if (ret != xpSuccess) { - XPC_DEACTIVATE_PARTITION(part, ret); - - dev_dbg(xpc_chan, "failed to pull openclose args from " - "partition %d, ret=%d\n", XPC_PARTID(part), - ret); - - /* don't bother processing IPIs anymore */ - IPI_amo = 0; - } - } - - if (XPC_ANY_MSG_IPI_FLAGS_SET(IPI_amo)) { - ret = xpc_pull_remote_cachelines(part, part->remote_GPs, - (void *)part->remote_GPs_pa, - XPC_GP_SIZE); - if (ret != xpSuccess) { - XPC_DEACTIVATE_PARTITION(part, ret); - - dev_dbg(xpc_chan, "failed to pull GPs from partition " - "%d, ret=%d\n", XPC_PARTID(part), ret); - - /* don't bother processing IPIs anymore */ - IPI_amo = 0; - } - } - - return IPI_amo; -} - /* * Allocate the local message queue and the notify queue. */ @@ -1364,59 +988,6 @@ xpc_partition_going_down(struct xpc_partition *part, enum xp_retval reason) xpc_part_deref(part); } -/* - * Teardown the infrastructure necessary to support XPartition Communication - * between the specified remote partition and the local one. - */ -void -xpc_teardown_infrastructure(struct xpc_partition *part) -{ - short partid = XPC_PARTID(part); - - /* - * We start off by making this partition inaccessible to local - * processes by marking it as no longer setup. Then we make it - * inaccessible to remote processes by clearing the XPC per partition - * specific variable's magic # (which indicates that these variables - * are no longer valid) and by ignoring all XPC notify IPIs sent to - * this partition. - */ - - DBUG_ON(atomic_read(&part->nchannels_engaged) != 0); - DBUG_ON(atomic_read(&part->nchannels_active) != 0); - DBUG_ON(part->setup_state != XPC_P_SETUP); - part->setup_state = XPC_P_WTEARDOWN; - - xpc_vars_part[partid].magic = 0; - - free_irq(SGI_XPC_NOTIFY, (void *)(u64)partid); - - /* - * Before proceeding with the teardown we have to wait until all - * existing references cease. - */ - wait_event(part->teardown_wq, (atomic_read(&part->references) == 0)); - - /* now we can begin tearing down the infrastructure */ - - part->setup_state = XPC_P_TORNDOWN; - - /* in case we've still got outstanding timers registered... */ - del_timer_sync(&part->dropped_IPI_timer); - - kfree(part->remote_openclose_args_base); - part->remote_openclose_args = NULL; - kfree(part->local_openclose_args_base); - part->local_openclose_args = NULL; - kfree(part->remote_GPs_base); - part->remote_GPs = NULL; - kfree(part->local_GPs_base); - part->local_GPs = NULL; - kfree(part->channels); - part->channels = NULL; - part->local_IPI_amo_va = NULL; -} - /* * Called by XP at the time of channel connection registration to cause * XPC to establish connections to all currently active partitions. @@ -1974,113 +1545,6 @@ xpc_initiate_send_notify(short partid, int ch_number, void *payload, return ret; } -static struct xpc_msg * -xpc_pull_remote_msg(struct xpc_channel *ch, s64 get) -{ - struct xpc_partition *part = &xpc_partitions[ch->partid]; - struct xpc_msg *remote_msg, *msg; - u32 msg_index, nmsgs; - u64 msg_offset; - enum xp_retval ret; - - if (mutex_lock_interruptible(&ch->msg_to_pull_mutex) != 0) { - /* we were interrupted by a signal */ - return NULL; - } - - while (get >= ch->next_msg_to_pull) { - - /* pull as many messages as are ready and able to be pulled */ - - msg_index = ch->next_msg_to_pull % ch->remote_nentries; - - DBUG_ON(ch->next_msg_to_pull >= ch->w_remote_GP.put); - nmsgs = ch->w_remote_GP.put - ch->next_msg_to_pull; - if (msg_index + nmsgs > ch->remote_nentries) { - /* ignore the ones that wrap the msg queue for now */ - nmsgs = ch->remote_nentries - msg_index; - } - - msg_offset = msg_index * ch->msg_size; - msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + msg_offset); - remote_msg = (struct xpc_msg *)(ch->remote_msgqueue_pa + - msg_offset); - - ret = xpc_pull_remote_cachelines(part, msg, remote_msg, - nmsgs * ch->msg_size); - if (ret != xpSuccess) { - - dev_dbg(xpc_chan, "failed to pull %d msgs starting with" - " msg %ld from partition %d, channel=%d, " - "ret=%d\n", nmsgs, ch->next_msg_to_pull, - ch->partid, ch->number, ret); - - XPC_DEACTIVATE_PARTITION(part, ret); - - mutex_unlock(&ch->msg_to_pull_mutex); - return NULL; - } - - ch->next_msg_to_pull += nmsgs; - } - - mutex_unlock(&ch->msg_to_pull_mutex); - - /* return the message we were looking for */ - msg_offset = (get % ch->remote_nentries) * ch->msg_size; - msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + msg_offset); - - return msg; -} - -/* - * Get a message to be delivered. - */ -static struct xpc_msg * -xpc_get_deliverable_msg(struct xpc_channel *ch) -{ - struct xpc_msg *msg = NULL; - s64 get; - - do { - if (ch->flags & XPC_C_DISCONNECTING) - break; - - get = ch->w_local_GP.get; - rmb(); /* guarantee that .get loads before .put */ - if (get == ch->w_remote_GP.put) - break; - - /* There are messages waiting to be pulled and delivered. - * We need to try to secure one for ourselves. We'll do this - * by trying to increment w_local_GP.get and hope that no one - * else beats us to it. If they do, we'll we'll simply have - * to try again for the next one. - */ - - if (cmpxchg(&ch->w_local_GP.get, get, get + 1) == get) { - /* we got the entry referenced by get */ - - dev_dbg(xpc_chan, "w_local_GP.get changed to %ld, " - "partid=%d, channel=%d\n", get + 1, - ch->partid, ch->number); - - /* pull the message from the remote partition */ - - msg = xpc_pull_remote_msg(ch, get); - - DBUG_ON(msg != NULL && msg->number != get); - DBUG_ON(msg != NULL && (msg->flags & XPC_M_DONE)); - DBUG_ON(msg != NULL && !(msg->flags & XPC_M_READY)); - - break; - } - - } while (1); - - return msg; -} - /* * Deliver a message to its intended recipient. */ diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index 2180f1f7e08..be3a4853930 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -176,6 +176,12 @@ static struct notifier_block xpc_die_notifier = { }; enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *rp); +enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *part); +u64 (*xpc_get_IPI_flags) (struct xpc_partition *part); +struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *ch); +enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *part); +void (*xpc_teardown_infrastructure) (struct xpc_partition *part); + /* * Timer function to enforce the timelimit on the partition disengage request. @@ -312,38 +318,9 @@ xpc_initiate_discovery(void *ignore) return 0; } -/* - * Establish first contact with the remote partititon. This involves pulling - * the XPC per partition variables from the remote partition and waiting for - * the remote partition to pull ours. - */ -static enum xp_retval -xpc_make_first_contact(struct xpc_partition *part) -{ - enum xp_retval ret; - - while ((ret = xpc_pull_remote_vars_part(part)) != xpSuccess) { - if (ret != xpRetry) { - XPC_DEACTIVATE_PARTITION(part, ret); - return ret; - } - - dev_dbg(xpc_chan, "waiting to make first contact with " - "partition %d\n", XPC_PARTID(part)); - - /* wait a 1/4 of a second or so */ - (void)msleep_interruptible(250); - - if (part->act_state == XPC_P_DEACTIVATING) - return part->reason; - } - - return xpc_mark_partition_active(part); -} - /* * The first kthread assigned to a newly activated partition is the one - * created by XPC HB with which it calls xpc_partition_up(). XPC hangs on to + * created by XPC HB with which it calls xpc_activating(). XPC hangs on to * that kthread until the partition is brought down, at which time that kthread * returns back to XPC HB. (The return of that kthread will signify to XPC HB * that XPC has dismantled all communication infrastructure for the associated @@ -393,41 +370,10 @@ xpc_channel_mgr(struct xpc_partition *part) * upped partition. * * The kthread that was created by XPC HB and which setup the XPC - * infrastructure will remain assigned to the partition until the partition - * goes down. At which time the kthread will teardown the XPC infrastructure - * and then exit. - * - * XPC HB will put the remote partition's XPC per partition specific variables - * physical address into xpc_partitions[partid].remote_vars_part_pa prior to - * calling xpc_partition_up(). + * infrastructure will remain assigned to the partition becoming the channel + * manager for that partition until the partition is deactivating, at which + * time the kthread will teardown the XPC infrastructure and then exit. */ -static void -xpc_partition_up(struct xpc_partition *part) -{ - DBUG_ON(part->channels != NULL); - - dev_dbg(xpc_chan, "activating partition %d\n", XPC_PARTID(part)); - - if (xpc_setup_infrastructure(part) != xpSuccess) - return; - - /* - * The kthread that XPC HB called us with will become the - * channel manager for this partition. It will not return - * back to XPC HB until the partition's XPC infrastructure - * has been dismantled. - */ - - (void)xpc_part_ref(part); /* this will always succeed */ - - if (xpc_make_first_contact(part) == xpSuccess) - xpc_channel_mgr(part); - - xpc_part_deref(part); - - xpc_teardown_infrastructure(part); -} - static int xpc_activating(void *__partid) { @@ -453,7 +399,7 @@ xpc_activating(void *__partid) XPC_SET_REASON(part, 0, 0); spin_unlock_irqrestore(&part->act_lock, irq_flags); - dev_dbg(xpc_part, "bringing partition %d up\n", partid); + dev_dbg(xpc_part, "activating partition %d\n", partid); /* * Register the remote partition's AMOs with SAL so it can handle @@ -467,7 +413,7 @@ xpc_activating(void *__partid) */ if (sn_register_xp_addr_region(part->remote_amos_page_pa, PAGE_SIZE, 1) < 0) { - dev_warn(xpc_part, "xpc_partition_up(%d) failed to register " + dev_warn(xpc_part, "xpc_activating(%d) failed to register " "xp_addr region\n", partid); spin_lock_irqsave(&part->act_lock, irq_flags); @@ -481,11 +427,18 @@ xpc_activating(void *__partid) xpc_allow_hb(partid, xpc_vars); xpc_IPI_send_activated(part); - /* - * xpc_partition_up() holds this thread and marks this partition as - * XPC_P_ACTIVE by calling xpc_hb_mark_active(). - */ - (void)xpc_partition_up(part); + if (xpc_setup_infrastructure(part) == xpSuccess) { + (void)xpc_part_ref(part); /* this will always succeed */ + + if (xpc_make_first_contact(part) == xpSuccess) { + xpc_mark_partition_active(part); + xpc_channel_mgr(part); + /* won't return until partition is deactivating */ + } + + xpc_part_deref(part); + xpc_teardown_infrastructure(part); + } xpc_disallow_hb(partid, xpc_vars); xpc_mark_partition_inactive(part); @@ -568,7 +521,7 @@ xpc_dropped_IPI_check(struct xpc_partition *part) xpc_check_for_channel_activity(part); part->dropped_IPI_timer.expires = jiffies + - XPC_P_DROPPED_IPI_WAIT; + XPC_P_DROPPED_IPI_WAIT_INTERVAL; add_timer(&part->dropped_IPI_timer); xpc_part_deref(part); } diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 1db84cb4914..be5b7547dab 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -486,6 +486,7 @@ xpc_update_partition_info(struct xpc_partition *part, u8 remote_rp_version, dev_dbg(xpc_part, " last_heartbeat = 0x%016lx\n", part->last_heartbeat); +/* >>> remote_vars_part_pa and vars_part_pa are sn2 only!!! */ part->remote_vars_part_pa = remote_vars->vars_part_pa; dev_dbg(xpc_part, " remote_vars_part_pa = 0x%016lx\n", part->remote_vars_part_pa); diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index 5a37348715c..ee28e231dc4 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -14,12 +14,13 @@ */ #include +#include #include #include #include "xpc.h" struct xpc_vars *xpc_vars; -struct xpc_vars_part *xpc_vars_part; +static struct xpc_vars_part_sn2 *xpc_vars_part; /* >>> Add _sn2 suffix? */ static enum xp_retval xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) @@ -33,7 +34,10 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) rp->sn.vars_pa = __pa(xpc_vars); - xpc_vars_part = XPC_RP_VARS_PART(rp); + /* vars_part array follows immediately after vars */ + xpc_vars_part = (struct xpc_vars_part_sn2 *)((u8 *)XPC_RP_VARS(rp) + + XPC_RP_VARS_SIZE); + /* * Before clearing xpc_vars, see if a page of AMOs had been previously @@ -85,7 +89,7 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) xpc_vars->amos_page = amos_page; /* save for next load of XPC */ /* clear xpc_vars_part */ - memset((u64 *)xpc_vars_part, 0, sizeof(struct xpc_vars_part) * + memset((u64 *)xpc_vars_part, 0, sizeof(struct xpc_vars_part_sn2) * xp_max_npartitions); /* initialize the activate IRQ related AMO variables */ @@ -99,10 +103,563 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) return xpSuccess; } +/* + * Setup the infrastructure necessary to support XPartition Communication + * between the specified remote partition and the local one. + */ +static enum xp_retval +xpc_setup_infrastructure_sn2(struct xpc_partition *part) +{ + enum xp_retval retval; + int ret; + int cpuid; + int ch_number; + struct xpc_channel *ch; + struct timer_list *timer; + short partid = XPC_PARTID(part); + + /* + * Allocate all of the channel structures as a contiguous chunk of + * memory. + */ + DBUG_ON(part->channels != NULL); + part->channels = kzalloc(sizeof(struct xpc_channel) * XPC_MAX_NCHANNELS, + GFP_KERNEL); + if (part->channels == NULL) { + dev_err(xpc_chan, "can't get memory for channels\n"); + return xpNoMemory; + } + + /* allocate all the required GET/PUT values */ + + part->local_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, + GFP_KERNEL, + &part->local_GPs_base); + if (part->local_GPs == NULL) { + dev_err(xpc_chan, "can't get memory for local get/put " + "values\n"); + retval = xpNoMemory; + goto out_1; + } + + part->remote_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, + GFP_KERNEL, + &part-> + remote_GPs_base); + if (part->remote_GPs == NULL) { + dev_err(xpc_chan, "can't get memory for remote get/put " + "values\n"); + retval = xpNoMemory; + goto out_2; + } + + part->remote_GPs_pa = 0; + + /* allocate all the required open and close args */ + + part->local_openclose_args = + xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL, + &part->local_openclose_args_base); + if (part->local_openclose_args == NULL) { + dev_err(xpc_chan, "can't get memory for local connect args\n"); + retval = xpNoMemory; + goto out_3; + } + + part->remote_openclose_args = + xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL, + &part->remote_openclose_args_base); + if (part->remote_openclose_args == NULL) { + dev_err(xpc_chan, "can't get memory for remote connect args\n"); + retval = xpNoMemory; + goto out_4; + } + + part->remote_openclose_args_pa = 0; + + part->local_IPI_amo_va = xpc_IPI_init(partid); + part->local_IPI_amo = 0; + spin_lock_init(&part->IPI_lock); + + part->remote_IPI_nasid = 0; + part->remote_IPI_phys_cpuid = 0; + part->remote_IPI_amo_va = NULL; + + atomic_set(&part->channel_mgr_requests, 1); + init_waitqueue_head(&part->channel_mgr_wq); + + sprintf(part->IPI_owner, "xpc%02d", partid); + ret = request_irq(SGI_XPC_NOTIFY, xpc_notify_IRQ_handler, IRQF_SHARED, + part->IPI_owner, (void *)(u64)partid); + if (ret != 0) { + dev_err(xpc_chan, "can't register NOTIFY IRQ handler, " + "errno=%d\n", -ret); + retval = xpLackOfResources; + goto out_5; + } + + /* Setup a timer to check for dropped IPIs */ + timer = &part->dropped_IPI_timer; + init_timer(timer); + timer->function = (void (*)(unsigned long))xpc_dropped_IPI_check; + timer->data = (unsigned long)part; + timer->expires = jiffies + XPC_P_DROPPED_IPI_WAIT_INTERVAL; + add_timer(timer); + + part->nchannels = XPC_MAX_NCHANNELS; + + atomic_set(&part->nchannels_active, 0); + atomic_set(&part->nchannels_engaged, 0); + + for (ch_number = 0; ch_number < part->nchannels; ch_number++) { + ch = &part->channels[ch_number]; + + ch->partid = partid; + ch->number = ch_number; + ch->flags = XPC_C_DISCONNECTED; + + ch->local_GP = &part->local_GPs[ch_number]; + ch->local_openclose_args = + &part->local_openclose_args[ch_number]; + + atomic_set(&ch->kthreads_assigned, 0); + atomic_set(&ch->kthreads_idle, 0); + atomic_set(&ch->kthreads_active, 0); + + atomic_set(&ch->references, 0); + atomic_set(&ch->n_to_notify, 0); + + spin_lock_init(&ch->lock); + mutex_init(&ch->msg_to_pull_mutex); + init_completion(&ch->wdisconnect_wait); + + atomic_set(&ch->n_on_msg_allocate_wq, 0); + init_waitqueue_head(&ch->msg_allocate_wq); + init_waitqueue_head(&ch->idle_wq); + } + + /* + * With the setting of the partition setup_state to XPC_P_SETUP, we're + * declaring that this partition is ready to go. + */ + part->setup_state = XPC_P_SETUP; + + /* + * Setup the per partition specific variables required by the + * remote partition to establish channel connections with us. + * + * The setting of the magic # indicates that these per partition + * specific variables are ready to be used. + */ + xpc_vars_part[partid].GPs_pa = __pa(part->local_GPs); + xpc_vars_part[partid].openclose_args_pa = + __pa(part->local_openclose_args); + xpc_vars_part[partid].IPI_amo_pa = __pa(part->local_IPI_amo_va); + cpuid = raw_smp_processor_id(); /* any CPU in this partition will do */ + xpc_vars_part[partid].IPI_nasid = cpuid_to_nasid(cpuid); + xpc_vars_part[partid].IPI_phys_cpuid = cpu_physical_id(cpuid); + xpc_vars_part[partid].nchannels = part->nchannels; + xpc_vars_part[partid].magic = XPC_VP_MAGIC1; + + return xpSuccess; + + /* setup of infrastructure failed */ +out_5: + kfree(part->remote_openclose_args_base); + part->remote_openclose_args = NULL; +out_4: + kfree(part->local_openclose_args_base); + part->local_openclose_args = NULL; +out_3: + kfree(part->remote_GPs_base); + part->remote_GPs = NULL; +out_2: + kfree(part->local_GPs_base); + part->local_GPs = NULL; +out_1: + kfree(part->channels); + part->channels = NULL; + return retval; +} + +/* + * Teardown the infrastructure necessary to support XPartition Communication + * between the specified remote partition and the local one. + */ +static void +xpc_teardown_infrastructure_sn2(struct xpc_partition *part) +{ + short partid = XPC_PARTID(part); + + /* + * We start off by making this partition inaccessible to local + * processes by marking it as no longer setup. Then we make it + * inaccessible to remote processes by clearing the XPC per partition + * specific variable's magic # (which indicates that these variables + * are no longer valid) and by ignoring all XPC notify IPIs sent to + * this partition. + */ + + DBUG_ON(atomic_read(&part->nchannels_engaged) != 0); + DBUG_ON(atomic_read(&part->nchannels_active) != 0); + DBUG_ON(part->setup_state != XPC_P_SETUP); + part->setup_state = XPC_P_WTEARDOWN; + + xpc_vars_part[partid].magic = 0; + + free_irq(SGI_XPC_NOTIFY, (void *)(u64)partid); + + /* + * Before proceeding with the teardown we have to wait until all + * existing references cease. + */ + wait_event(part->teardown_wq, (atomic_read(&part->references) == 0)); + + /* now we can begin tearing down the infrastructure */ + + part->setup_state = XPC_P_TORNDOWN; + + /* in case we've still got outstanding timers registered... */ + del_timer_sync(&part->dropped_IPI_timer); + + kfree(part->remote_openclose_args_base); + part->remote_openclose_args = NULL; + kfree(part->local_openclose_args_base); + part->local_openclose_args = NULL; + kfree(part->remote_GPs_base); + part->remote_GPs = NULL; + kfree(part->local_GPs_base); + part->local_GPs = NULL; + kfree(part->channels); + part->channels = NULL; + part->local_IPI_amo_va = NULL; +} + +/* + * Create a wrapper that hides the underlying mechanism for pulling a cacheline + * (or multiple cachelines) from a remote partition. + * + * src must be a cacheline aligned physical address on the remote partition. + * dst must be a cacheline aligned virtual address on this partition. + * cnt must be cacheline sized + */ +/* >>> Replace this function by call to xp_remote_memcpy() or bte_copy()? */ +static enum xp_retval +xpc_pull_remote_cachelines_sn2(struct xpc_partition *part, void *dst, + const void *src, size_t cnt) +{ + enum xp_retval ret; + + DBUG_ON((u64)src != L1_CACHE_ALIGN((u64)src)); + DBUG_ON((u64)dst != L1_CACHE_ALIGN((u64)dst)); + DBUG_ON(cnt != L1_CACHE_ALIGN(cnt)); + + if (part->act_state == XPC_P_DEACTIVATING) + return part->reason; + + ret = xp_remote_memcpy(dst, src, cnt); + if (ret != xpSuccess) { + dev_dbg(xpc_chan, "xp_remote_memcpy() from partition %d failed," + " ret=%d\n", XPC_PARTID(part), ret); + } + return ret; +} + +/* + * Pull the remote per partition specific variables from the specified + * partition. + */ +static enum xp_retval +xpc_pull_remote_vars_part_sn2(struct xpc_partition *part) +{ + u8 buffer[L1_CACHE_BYTES * 2]; + struct xpc_vars_part_sn2 *pulled_entry_cacheline = + (struct xpc_vars_part_sn2 *)L1_CACHE_ALIGN((u64)buffer); + struct xpc_vars_part_sn2 *pulled_entry; + u64 remote_entry_cacheline_pa, remote_entry_pa; + short partid = XPC_PARTID(part); + enum xp_retval ret; + + /* pull the cacheline that contains the variables we're interested in */ + + DBUG_ON(part->remote_vars_part_pa != + L1_CACHE_ALIGN(part->remote_vars_part_pa)); + DBUG_ON(sizeof(struct xpc_vars_part_sn2) != L1_CACHE_BYTES / 2); + + remote_entry_pa = part->remote_vars_part_pa + + sn_partition_id * sizeof(struct xpc_vars_part_sn2); + + remote_entry_cacheline_pa = (remote_entry_pa & ~(L1_CACHE_BYTES - 1)); + + pulled_entry = (struct xpc_vars_part_sn2 *)((u64)pulled_entry_cacheline + + (remote_entry_pa & + (L1_CACHE_BYTES - 1))); + + ret = xpc_pull_remote_cachelines_sn2(part, pulled_entry_cacheline, + (void *)remote_entry_cacheline_pa, + L1_CACHE_BYTES); + if (ret != xpSuccess) { + dev_dbg(xpc_chan, "failed to pull XPC vars_part from " + "partition %d, ret=%d\n", partid, ret); + return ret; + } + + /* see if they've been set up yet */ + + if (pulled_entry->magic != XPC_VP_MAGIC1 && + pulled_entry->magic != XPC_VP_MAGIC2) { + + if (pulled_entry->magic != 0) { + dev_dbg(xpc_chan, "partition %d's XPC vars_part for " + "partition %d has bad magic value (=0x%lx)\n", + partid, sn_partition_id, pulled_entry->magic); + return xpBadMagic; + } + + /* they've not been initialized yet */ + return xpRetry; + } + + if (xpc_vars_part[partid].magic == XPC_VP_MAGIC1) { + + /* validate the variables */ + + if (pulled_entry->GPs_pa == 0 || + pulled_entry->openclose_args_pa == 0 || + pulled_entry->IPI_amo_pa == 0) { + + dev_err(xpc_chan, "partition %d's XPC vars_part for " + "partition %d are not valid\n", partid, + sn_partition_id); + return xpInvalidAddress; + } + + /* the variables we imported look to be valid */ + + part->remote_GPs_pa = pulled_entry->GPs_pa; + part->remote_openclose_args_pa = + pulled_entry->openclose_args_pa; + part->remote_IPI_amo_va = + (AMO_t *)__va(pulled_entry->IPI_amo_pa); + part->remote_IPI_nasid = pulled_entry->IPI_nasid; + part->remote_IPI_phys_cpuid = pulled_entry->IPI_phys_cpuid; + + if (part->nchannels > pulled_entry->nchannels) + part->nchannels = pulled_entry->nchannels; + + /* let the other side know that we've pulled their variables */ + + xpc_vars_part[partid].magic = XPC_VP_MAGIC2; + } + + if (pulled_entry->magic == XPC_VP_MAGIC1) + return xpRetry; + + return xpSuccess; +} + +/* + * Establish first contact with the remote partititon. This involves pulling + * the XPC per partition variables from the remote partition and waiting for + * the remote partition to pull ours. + */ +static enum xp_retval +xpc_make_first_contact_sn2(struct xpc_partition *part) +{ + enum xp_retval ret; + + while ((ret = xpc_pull_remote_vars_part_sn2(part)) != xpSuccess) { + if (ret != xpRetry) { + XPC_DEACTIVATE_PARTITION(part, ret); + return ret; + } + + dev_dbg(xpc_part, "waiting to make first contact with " + "partition %d\n", XPC_PARTID(part)); + + /* wait a 1/4 of a second or so */ + (void)msleep_interruptible(250); + + if (part->act_state == XPC_P_DEACTIVATING) + return part->reason; + } + + return xpSuccess; +} + +/* + * Get the IPI flags and pull the openclose args and/or remote GPs as needed. + */ +static u64 +xpc_get_IPI_flags_sn2(struct xpc_partition *part) +{ + unsigned long irq_flags; + u64 IPI_amo; + enum xp_retval ret; + + /* + * See if there are any IPI flags to be handled. + */ + + spin_lock_irqsave(&part->IPI_lock, irq_flags); + IPI_amo = part->local_IPI_amo; + if (IPI_amo != 0) + part->local_IPI_amo = 0; + + spin_unlock_irqrestore(&part->IPI_lock, irq_flags); + + if (XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(IPI_amo)) { + ret = xpc_pull_remote_cachelines_sn2(part, + part->remote_openclose_args, + (void *)part-> + remote_openclose_args_pa, + XPC_OPENCLOSE_ARGS_SIZE); + if (ret != xpSuccess) { + XPC_DEACTIVATE_PARTITION(part, ret); + + dev_dbg(xpc_chan, "failed to pull openclose args from " + "partition %d, ret=%d\n", XPC_PARTID(part), + ret); + + /* don't bother processing IPIs anymore */ + IPI_amo = 0; + } + } + + if (XPC_ANY_MSG_IPI_FLAGS_SET(IPI_amo)) { + ret = xpc_pull_remote_cachelines_sn2(part, part->remote_GPs, + (void *)part->remote_GPs_pa, + XPC_GP_SIZE); + if (ret != xpSuccess) { + XPC_DEACTIVATE_PARTITION(part, ret); + + dev_dbg(xpc_chan, "failed to pull GPs from partition " + "%d, ret=%d\n", XPC_PARTID(part), ret); + + /* don't bother processing IPIs anymore */ + IPI_amo = 0; + } + } + + return IPI_amo; +} + +static struct xpc_msg * +xpc_pull_remote_msg_sn2(struct xpc_channel *ch, s64 get) +{ + struct xpc_partition *part = &xpc_partitions[ch->partid]; + struct xpc_msg *remote_msg, *msg; + u32 msg_index, nmsgs; + u64 msg_offset; + enum xp_retval ret; + + if (mutex_lock_interruptible(&ch->msg_to_pull_mutex) != 0) { + /* we were interrupted by a signal */ + return NULL; + } + + while (get >= ch->next_msg_to_pull) { + + /* pull as many messages as are ready and able to be pulled */ + + msg_index = ch->next_msg_to_pull % ch->remote_nentries; + + DBUG_ON(ch->next_msg_to_pull >= ch->w_remote_GP.put); + nmsgs = ch->w_remote_GP.put - ch->next_msg_to_pull; + if (msg_index + nmsgs > ch->remote_nentries) { + /* ignore the ones that wrap the msg queue for now */ + nmsgs = ch->remote_nentries - msg_index; + } + + msg_offset = msg_index * ch->msg_size; + msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + msg_offset); + remote_msg = (struct xpc_msg *)(ch->remote_msgqueue_pa + + msg_offset); + + ret = xpc_pull_remote_cachelines_sn2(part, msg, remote_msg, + nmsgs * ch->msg_size); + if (ret != xpSuccess) { + + dev_dbg(xpc_chan, "failed to pull %d msgs starting with" + " msg %ld from partition %d, channel=%d, " + "ret=%d\n", nmsgs, ch->next_msg_to_pull, + ch->partid, ch->number, ret); + + XPC_DEACTIVATE_PARTITION(part, ret); + + mutex_unlock(&ch->msg_to_pull_mutex); + return NULL; + } + + ch->next_msg_to_pull += nmsgs; + } + + mutex_unlock(&ch->msg_to_pull_mutex); + + /* return the message we were looking for */ + msg_offset = (get % ch->remote_nentries) * ch->msg_size; + msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + msg_offset); + + return msg; +} + +/* + * Get a message to be delivered. + */ +static struct xpc_msg * +xpc_get_deliverable_msg_sn2(struct xpc_channel *ch) +{ + struct xpc_msg *msg = NULL; + s64 get; + + do { + if (ch->flags & XPC_C_DISCONNECTING) + break; + + get = ch->w_local_GP.get; + rmb(); /* guarantee that .get loads before .put */ + if (get == ch->w_remote_GP.put) + break; + + /* There are messages waiting to be pulled and delivered. + * We need to try to secure one for ourselves. We'll do this + * by trying to increment w_local_GP.get and hope that no one + * else beats us to it. If they do, we'll we'll simply have + * to try again for the next one. + */ + + if (cmpxchg(&ch->w_local_GP.get, get, get + 1) == get) { + /* we got the entry referenced by get */ + + dev_dbg(xpc_chan, "w_local_GP.get changed to %ld, " + "partid=%d, channel=%d\n", get + 1, + ch->partid, ch->number); + + /* pull the message from the remote partition */ + + msg = xpc_pull_remote_msg_sn2(ch, get); + + DBUG_ON(msg != NULL && msg->number != get); + DBUG_ON(msg != NULL && (msg->flags & XPC_M_DONE)); + DBUG_ON(msg != NULL && !(msg->flags & XPC_M_READY)); + + break; + } + + } while (1); + + return msg; +} + void xpc_init_sn2(void) { xpc_rsvd_page_init = xpc_rsvd_page_init_sn2; + xpc_setup_infrastructure = xpc_setup_infrastructure_sn2; + xpc_teardown_infrastructure = xpc_teardown_infrastructure_sn2; + xpc_make_first_contact = xpc_make_first_contact_sn2; + xpc_get_IPI_flags = xpc_get_IPI_flags_sn2; + xpc_get_deliverable_msg = xpc_get_deliverable_msg_sn2; } void diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index 8327cd4017e..770f0a8c669 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c @@ -36,10 +36,58 @@ xpc_rsvd_page_init_uv(struct xpc_rsvd_page *rp) return xpSuccess; } +/* + * Setup the infrastructure necessary to support XPartition Communication + * between the specified remote partition and the local one. + */ +static enum xp_retval +xpc_setup_infrastructure_uv(struct xpc_partition *part) +{ + /* >>> this function needs fleshing out */ + return xpUnsupported; +} + +/* + * Teardown the infrastructure necessary to support XPartition Communication + * between the specified remote partition and the local one. + */ +static void +xpc_teardown_infrastructure_uv(struct xpc_partition *part) +{ + /* >>> this function needs fleshing out */ + return; +} + +static enum xp_retval +xpc_make_first_contact_uv(struct xpc_partition *part) +{ + /* >>> this function needs fleshing out */ + return xpUnsupported; +} + +static u64 +xpc_get_IPI_flags_uv(struct xpc_partition *part) +{ + /* >>> this function needs fleshing out */ + return 0UL; +} + +static struct xpc_msg * +xpc_get_deliverable_msg_uv(struct xpc_channel *ch) +{ + /* >>> this function needs fleshing out */ + return NULL; +} + void xpc_init_uv(void) { xpc_rsvd_page_init = xpc_rsvd_page_init_uv; + xpc_setup_infrastructure = xpc_setup_infrastructure_uv; + xpc_teardown_infrastructure = xpc_teardown_infrastructure_uv; + xpc_make_first_contact = xpc_make_first_contact_uv; + xpc_get_IPI_flags = xpc_get_IPI_flags_uv; + xpc_get_deliverable_msg = xpc_get_deliverable_msg_uv; } void -- cgit v1.2.3 From 33ba3c7724be79f7cdbfc611335572c056d9a05a Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:07 -0700 Subject: sgi-xp: isolate xpc_vars structure to sn2 only Isolate the xpc_vars structure of XPC's reserved page to sn2 only. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xpc.h | 529 +++------------- drivers/misc/sgi-xp/xpc_channel.c | 315 +--------- drivers/misc/sgi-xp/xpc_main.c | 152 +++-- drivers/misc/sgi-xp/xpc_partition.c | 454 +------------- drivers/misc/sgi-xp/xpc_sn2.c | 1181 ++++++++++++++++++++++++++++++++++- drivers/misc/sgi-xp/xpc_uv.c | 57 +- 6 files changed, 1433 insertions(+), 1255 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index e8c2a162960..a3a67485cf8 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -159,10 +159,10 @@ xpc_compare_stamps(struct timespec *stamp1, struct timespec *stamp2) * reflected by incrementing either the major or minor version numbers * of struct xpc_vars. */ -struct xpc_vars { +struct xpc_vars_sn2 { u8 version; u64 heartbeat; - u64 heartbeating_to_mask; + DECLARE_BITMAP(heartbeating_to_mask, XP_MAX_NPARTITIONS_SN2); u64 heartbeat_offline; /* if 0, heartbeat should be changing */ int act_nasid; int act_phys_cpuid; @@ -176,46 +176,23 @@ struct xpc_vars { #define XPC_SUPPORTS_DISENGAGE_REQUEST(_version) \ (_version >= _XPC_VERSION(3, 1)) -static inline int -xpc_hb_allowed(short partid, struct xpc_vars *vars) -{ - return ((vars->heartbeating_to_mask & (1UL << partid)) != 0); -} - -static inline void -xpc_allow_hb(short partid, struct xpc_vars *vars) -{ - u64 old_mask, new_mask; - - do { - old_mask = vars->heartbeating_to_mask; - new_mask = (old_mask | (1UL << partid)); - } while (cmpxchg(&vars->heartbeating_to_mask, old_mask, new_mask) != - old_mask); -} - -static inline void -xpc_disallow_hb(short partid, struct xpc_vars *vars) -{ - u64 old_mask, new_mask; - - do { - old_mask = vars->heartbeating_to_mask; - new_mask = (old_mask & ~(1UL << partid)); - } while (cmpxchg(&vars->heartbeating_to_mask, old_mask, new_mask) != - old_mask); -} - /* - * The AMOs page consists of a number of AMO variables which are divided into - * four groups, The first two groups are used to identify an IRQ's sender. - * These two groups consist of 64 and 128 AMO variables respectively. The last - * two groups, consisting of just one AMO variable each, are used to identify - * the remote partitions that are currently engaged (from the viewpoint of - * the XPC running on the remote partition). + * The following pertains to ia64-sn2 only. + * + * Memory for XPC's AMO variables is allocated by the MSPEC driver. These + * pages are located in the lowest granule. The lowest granule uses 4k pages + * for cached references and an alternate TLB handler to never provide a + * cacheable mapping for the entire region. This will prevent speculative + * reading of cached copies of our lines from being issued which will cause + * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64 + * AMO variables (based on XP_MAX_NPARTITIONS_SN2) to identify the senders of + * NOTIFY IRQs, 128 AMO variables (based on XP_NASID_MASK_WORDS) to identify + * the senders of ACTIVATE IRQs, and 2 AMO variables to identify which remote + * partitions (i.e., XPCs) consider themselves currently engaged with the + * local XPC. */ -#define XPC_NOTIFY_IRQ_AMOS 0 -#define XPC_ACTIVATE_IRQ_AMOS (XPC_NOTIFY_IRQ_AMOS + XP_MAX_NPARTITIONS_SN2) +#define XPC_NOTIFY_IRQ_AMOS 0 +#define XPC_ACTIVATE_IRQ_AMOS (XPC_NOTIFY_IRQ_AMOS + XP_MAX_NPARTITIONS_SN2) #define XPC_ENGAGED_PARTITIONS_AMO (XPC_ACTIVATE_IRQ_AMOS + XP_NASID_MASK_WORDS) #define XPC_DISENGAGE_REQUEST_AMO (XPC_ENGAGED_PARTITIONS_AMO + 1) @@ -259,11 +236,11 @@ struct xpc_vars_part_sn2 { /* the reserved page sizes and offsets */ #define XPC_RP_HEADER_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_rsvd_page)) -#define XPC_RP_VARS_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_vars)) +#define XPC_RP_VARS_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_vars_sn2)) #define XPC_RP_PART_NASIDS(_rp) ((u64 *)((u8 *)(_rp) + XPC_RP_HEADER_SIZE)) #define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + xp_nasid_mask_words) -#define XPC_RP_VARS(_rp) ((struct xpc_vars *)(XPC_RP_MACH_NASIDS(_rp) + \ +#define XPC_RP_VARS(_rp) ((struct xpc_vars_sn2 *)(XPC_RP_MACH_NASIDS(_rp) + \ xp_nasid_mask_words)) /* @@ -344,6 +321,7 @@ struct xpc_notify { * allocated at the time a partition becomes active. The array contains one * of these structures for each potential channel connection to that partition. * +>>> sn2 only!!! * Each of these structures manages two message queues (circular buffers). * They are allocated at the time a channel connection is made. One of * these message queues (local_msgqueue) holds the locally created messages @@ -622,6 +600,9 @@ extern struct device *xpc_part; extern struct device *xpc_chan; extern int xpc_disengage_request_timelimit; extern int xpc_disengage_request_timedout; +extern atomic_t xpc_act_IRQ_rcvd; +extern wait_queue_head_t xpc_act_IRQ_wq; +extern void *xpc_heartbeating_to_mask; extern irqreturn_t xpc_notify_IRQ_handler(int, void *); extern void xpc_dropped_IPI_check(struct xpc_partition *); extern void xpc_activate_partition(struct xpc_partition *); @@ -629,15 +610,48 @@ extern void xpc_activate_kthreads(struct xpc_channel *, int); extern void xpc_create_kthreads(struct xpc_channel *, int, int); extern void xpc_disconnect_wait(int); extern enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *); +extern void (*xpc_heartbeat_init) (void); +extern void (*xpc_heartbeat_exit) (void); +extern void (*xpc_increment_heartbeat) (void); +extern void (*xpc_offline_heartbeat) (void); +extern void (*xpc_online_heartbeat) (void); +extern void (*xpc_check_remote_hb) (void); extern enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *); extern u64 (*xpc_get_IPI_flags) (struct xpc_partition *); extern struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *); +extern void (*xpc_initiate_partition_activation) (struct xpc_rsvd_page *, u64, + int); +extern void (*xpc_process_act_IRQ_rcvd) (int); extern enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *); extern void (*xpc_teardown_infrastructure) (struct xpc_partition *); +extern void (*xpc_mark_partition_engaged) (struct xpc_partition *); +extern void (*xpc_mark_partition_disengaged) (struct xpc_partition *); +extern void (*xpc_request_partition_disengage) (struct xpc_partition *); +extern void (*xpc_cancel_partition_disengage_request) (struct xpc_partition *); +extern u64 (*xpc_partition_engaged) (u64); +extern u64 (*xpc_partition_disengage_requested) (u64);; +extern void (*xpc_clear_partition_engaged) (u64); +extern void (*xpc_clear_partition_disengage_request) (u64); + +extern void (*xpc_IPI_send_local_activate) (int); +extern void (*xpc_IPI_send_activated) (struct xpc_partition *); +extern void (*xpc_IPI_send_local_reactivate) (int); +extern void (*xpc_IPI_send_disengage) (struct xpc_partition *); + +extern void (*xpc_IPI_send_closerequest) (struct xpc_channel *, + unsigned long *); +extern void (*xpc_IPI_send_closereply) (struct xpc_channel *, unsigned long *); +extern void (*xpc_IPI_send_openrequest) (struct xpc_channel *, unsigned long *); +extern void (*xpc_IPI_send_openreply) (struct xpc_channel *, unsigned long *); + +extern enum xp_retval (*xpc_allocate_msg) (struct xpc_channel *, u32, + struct xpc_msg **); +extern enum xp_retval (*xpc_send_msg) (struct xpc_channel *, struct xpc_msg *, + u8, xpc_notify_func, void *); +extern void (*xpc_received_msg) (struct xpc_channel *, struct xpc_msg *); /* found in xpc_sn2.c */ extern void xpc_init_sn2(void); -extern struct xpc_vars *xpc_vars; /*>>> eliminate from here */ /* found in xpc_uv.c */ extern void xpc_init_uv(void); @@ -646,6 +660,7 @@ extern void xpc_init_uv(void); extern int xpc_exiting; extern int xp_nasid_mask_words; extern struct xpc_rsvd_page *xpc_rsvd_page; +extern u64 *xpc_mach_nasids; extern struct xpc_partition *xpc_partitions; extern char *xpc_remote_copy_buffer; extern void *xpc_remote_copy_buffer_base; @@ -658,7 +673,8 @@ extern int xpc_partition_disengaged(struct xpc_partition *); extern enum xp_retval xpc_mark_partition_active(struct xpc_partition *); extern void xpc_mark_partition_inactive(struct xpc_partition *); extern void xpc_discovery(void); -extern void xpc_check_remote_hb(void); +extern enum xp_retval xpc_get_remote_rp(int, u64 *, struct xpc_rsvd_page *, + u64 *); extern void xpc_deactivate_partition(const int, struct xpc_partition *, enum xp_retval); extern enum xp_retval xpc_initiate_partid_to_nasids(short, void *); @@ -667,6 +683,7 @@ extern enum xp_retval xpc_initiate_partid_to_nasids(short, void *); extern void *xpc_kzalloc_cacheline_aligned(size_t, gfp_t, void **); extern void xpc_initiate_connect(int); extern void xpc_initiate_disconnect(int); +extern enum xp_retval xpc_allocate_msg_wait(struct xpc_channel *); extern enum xp_retval xpc_initiate_allocate(short, int, u32, void **); extern enum xp_retval xpc_initiate_send(short, int, void *); extern enum xp_retval xpc_initiate_send_notify(short, int, void *, @@ -680,6 +697,40 @@ extern void xpc_disconnect_channel(const int, struct xpc_channel *, extern void xpc_disconnect_callout(struct xpc_channel *, enum xp_retval); extern void xpc_partition_going_down(struct xpc_partition *, enum xp_retval); +static inline int +xpc_hb_allowed(short partid, void *heartbeating_to_mask) +{ + return test_bit(partid, heartbeating_to_mask); +} + +static inline int +xpc_any_hbs_allowed(void) +{ + DBUG_ON(xpc_heartbeating_to_mask == NULL); + return !bitmap_empty(xpc_heartbeating_to_mask, xp_max_npartitions); +} + +static inline void +xpc_allow_hb(short partid) +{ + DBUG_ON(xpc_heartbeating_to_mask == NULL); + set_bit(partid, xpc_heartbeating_to_mask); +} + +static inline void +xpc_disallow_hb(short partid) +{ + DBUG_ON(xpc_heartbeating_to_mask == NULL); + clear_bit(partid, xpc_heartbeating_to_mask); +} + +static inline void +xpc_disallow_all_hbs(void) +{ + DBUG_ON(xpc_heartbeating_to_mask == NULL); + bitmap_zero(xpc_heartbeating_to_mask, xp_max_npartitions); +} + static inline void xpc_wakeup_channel_mgr(struct xpc_partition *part) { @@ -749,297 +800,7 @@ xpc_part_ref(struct xpc_partition *part) } /* - * This next set of inlines are used to keep track of when a partition is - * potentially engaged in accessing memory belonging to another partition. - */ - -static inline void -xpc_mark_partition_engaged(struct xpc_partition *part) -{ - unsigned long irq_flags; - AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + - (XPC_ENGAGED_PARTITIONS_AMO * - sizeof(AMO_t))); - - local_irq_save(irq_flags); - - /* set bit corresponding to our partid in remote partition's AMO */ - FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, - (1UL << sn_partition_id)); - /* - * We must always use the nofault function regardless of whether we - * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we - * didn't, we'd never know that the other partition is down and would - * keep sending IPIs and AMOs to it until the heartbeat times out. - */ - (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> - variable), - xp_nofault_PIOR_target)); - - local_irq_restore(irq_flags); -} - -static inline void -xpc_mark_partition_disengaged(struct xpc_partition *part) -{ - unsigned long irq_flags; - AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + - (XPC_ENGAGED_PARTITIONS_AMO * - sizeof(AMO_t))); - - local_irq_save(irq_flags); - - /* clear bit corresponding to our partid in remote partition's AMO */ - FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, - ~(1UL << sn_partition_id)); - /* - * We must always use the nofault function regardless of whether we - * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we - * didn't, we'd never know that the other partition is down and would - * keep sending IPIs and AMOs to it until the heartbeat times out. - */ - (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> - variable), - xp_nofault_PIOR_target)); - - local_irq_restore(irq_flags); -} - -static inline void -xpc_request_partition_disengage(struct xpc_partition *part) -{ - unsigned long irq_flags; - AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + - (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t))); - - local_irq_save(irq_flags); - - /* set bit corresponding to our partid in remote partition's AMO */ - FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, - (1UL << sn_partition_id)); - /* - * We must always use the nofault function regardless of whether we - * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we - * didn't, we'd never know that the other partition is down and would - * keep sending IPIs and AMOs to it until the heartbeat times out. - */ - (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> - variable), - xp_nofault_PIOR_target)); - - local_irq_restore(irq_flags); -} - -static inline void -xpc_cancel_partition_disengage_request(struct xpc_partition *part) -{ - unsigned long irq_flags; - AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + - (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t))); - - local_irq_save(irq_flags); - - /* clear bit corresponding to our partid in remote partition's AMO */ - FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, - ~(1UL << sn_partition_id)); - /* - * We must always use the nofault function regardless of whether we - * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we - * didn't, we'd never know that the other partition is down and would - * keep sending IPIs and AMOs to it until the heartbeat times out. - */ - (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> - variable), - xp_nofault_PIOR_target)); - - local_irq_restore(irq_flags); -} - -static inline u64 -xpc_partition_engaged(u64 partid_mask) -{ - AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; - - /* return our partition's AMO variable ANDed with partid_mask */ - return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & - partid_mask); -} - -static inline u64 -xpc_partition_disengage_requested(u64 partid_mask) -{ - AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO; - - /* return our partition's AMO variable ANDed with partid_mask */ - return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & - partid_mask); -} - -static inline void -xpc_clear_partition_engaged(u64 partid_mask) -{ - AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; - - /* clear bit(s) based on partid_mask in our partition's AMO */ - FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, - ~partid_mask); -} - -static inline void -xpc_clear_partition_disengage_request(u64 partid_mask) -{ - AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO; - - /* clear bit(s) based on partid_mask in our partition's AMO */ - FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, - ~partid_mask); -} - -/* - * The following set of macros and inlines are used for the sending and - * receiving of IPIs (also known as IRQs). There are two flavors of IPIs, - * one that is associated with partition activity (SGI_XPC_ACTIVATE) and - * the other that is associated with channel activity (SGI_XPC_NOTIFY). - */ - -static inline u64 -xpc_IPI_receive(AMO_t *amo) -{ - return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_CLEAR); -} - -static inline enum xp_retval -xpc_IPI_send(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector) -{ - int ret = 0; - unsigned long irq_flags; - - local_irq_save(irq_flags); - - FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, flag); - sn_send_IPI_phys(nasid, phys_cpuid, vector, 0); - - /* - * We must always use the nofault function regardless of whether we - * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we - * didn't, we'd never know that the other partition is down and would - * keep sending IPIs and AMOs to it until the heartbeat times out. - */ - ret = xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->variable), - xp_nofault_PIOR_target)); - - local_irq_restore(irq_flags); - - return ((ret == 0) ? xpSuccess : xpPioReadError); -} - -/* - * IPIs associated with SGI_XPC_ACTIVATE IRQ. - */ - -/* - * Flag the appropriate AMO variable and send an IPI to the specified node. - */ -static inline void -xpc_activate_IRQ_send(u64 amos_page_pa, int from_nasid, int to_nasid, - int to_phys_cpuid) -{ - int w_index = XPC_NASID_W_INDEX(from_nasid); - int b_index = XPC_NASID_B_INDEX(from_nasid); - AMO_t *amos = (AMO_t *)__va(amos_page_pa + - (XPC_ACTIVATE_IRQ_AMOS * sizeof(AMO_t))); - - (void)xpc_IPI_send(&amos[w_index], (1UL << b_index), to_nasid, - to_phys_cpuid, SGI_XPC_ACTIVATE); -} - -static inline void -xpc_IPI_send_activate(struct xpc_vars *vars) -{ - xpc_activate_IRQ_send(vars->amos_page_pa, cnodeid_to_nasid(0), - vars->act_nasid, vars->act_phys_cpuid); -} - -static inline void -xpc_IPI_send_activated(struct xpc_partition *part) -{ - xpc_activate_IRQ_send(part->remote_amos_page_pa, cnodeid_to_nasid(0), - part->remote_act_nasid, - part->remote_act_phys_cpuid); -} - -static inline void -xpc_IPI_send_reactivate(struct xpc_partition *part) -{ - xpc_activate_IRQ_send(xpc_vars->amos_page_pa, part->reactivate_nasid, - xpc_vars->act_nasid, xpc_vars->act_phys_cpuid); -} - -static inline void -xpc_IPI_send_disengage(struct xpc_partition *part) -{ - xpc_activate_IRQ_send(part->remote_amos_page_pa, cnodeid_to_nasid(0), - part->remote_act_nasid, - part->remote_act_phys_cpuid); -} - -/* - * IPIs associated with SGI_XPC_NOTIFY IRQ. - */ - -/* - * Send an IPI to the remote partition that is associated with the - * specified channel. - */ -#define XPC_NOTIFY_IRQ_SEND(_ch, _ipi_f, _irq_f) \ - xpc_notify_IRQ_send(_ch, _ipi_f, #_ipi_f, _irq_f) - -static inline void -xpc_notify_IRQ_send(struct xpc_channel *ch, u8 ipi_flag, char *ipi_flag_string, - unsigned long *irq_flags) -{ - struct xpc_partition *part = &xpc_partitions[ch->partid]; - enum xp_retval ret; - - if (likely(part->act_state != XPC_P_DEACTIVATING)) { - ret = xpc_IPI_send(part->remote_IPI_amo_va, - (u64)ipi_flag << (ch->number * 8), - part->remote_IPI_nasid, - part->remote_IPI_phys_cpuid, SGI_XPC_NOTIFY); - dev_dbg(xpc_chan, "%s sent to partid=%d, channel=%d, ret=%d\n", - ipi_flag_string, ch->partid, ch->number, ret); - if (unlikely(ret != xpSuccess)) { - if (irq_flags != NULL) - spin_unlock_irqrestore(&ch->lock, *irq_flags); - XPC_DEACTIVATE_PARTITION(part, ret); - if (irq_flags != NULL) - spin_lock_irqsave(&ch->lock, *irq_flags); - } - } -} - -/* - * Make it look like the remote partition, which is associated with the - * specified channel, sent us an IPI. This faked IPI will be handled - * by xpc_dropped_IPI_check(). - */ -#define XPC_NOTIFY_IRQ_SEND_LOCAL(_ch, _ipi_f) \ - xpc_notify_IRQ_send_local(_ch, _ipi_f, #_ipi_f) - -static inline void -xpc_notify_IRQ_send_local(struct xpc_channel *ch, u8 ipi_flag, - char *ipi_flag_string) -{ - struct xpc_partition *part = &xpc_partitions[ch->partid]; - - FETCHOP_STORE_OP(TO_AMO((u64)&part->local_IPI_amo_va->variable), - FETCHOP_OR, ((u64)ipi_flag << (ch->number * 8))); - dev_dbg(xpc_chan, "%s sent local from partid=%d, channel=%d\n", - ipi_flag_string, ch->partid, ch->number); -} - -/* - * The sending and receiving of IPIs includes the setting of an AMO variable + * The sending and receiving of IPIs includes the setting of an >>>AMO variable * to indicate the reason the IPI was sent. The 64-bit variable is divided * up into eight bytes, ordered from right to left. Byte zero pertains to * channel 0, byte one to channel 1, and so on. Each byte is described by @@ -1052,107 +813,11 @@ xpc_notify_IRQ_send_local(struct xpc_channel *ch, u8 ipi_flag, #define XPC_IPI_OPENREPLY 0x08 #define XPC_IPI_MSGREQUEST 0x10 -/* given an AMO variable and a channel#, get its associated IPI flags */ +/* given an >>>AMO variable and a channel#, get its associated IPI flags */ #define XPC_GET_IPI_FLAGS(_amo, _c) ((u8) (((_amo) >> ((_c) * 8)) & 0xff)) #define XPC_SET_IPI_FLAGS(_amo, _c, _f) (_amo) |= ((u64) (_f) << ((_c) * 8)) #define XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(_amo) ((_amo) & 0x0f0f0f0f0f0f0f0fUL) #define XPC_ANY_MSG_IPI_FLAGS_SET(_amo) ((_amo) & 0x1010101010101010UL) -static inline void -xpc_IPI_send_closerequest(struct xpc_channel *ch, unsigned long *irq_flags) -{ - struct xpc_openclose_args *args = ch->local_openclose_args; - - args->reason = ch->reason; - - XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_CLOSEREQUEST, irq_flags); -} - -static inline void -xpc_IPI_send_closereply(struct xpc_channel *ch, unsigned long *irq_flags) -{ - XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_CLOSEREPLY, irq_flags); -} - -static inline void -xpc_IPI_send_openrequest(struct xpc_channel *ch, unsigned long *irq_flags) -{ - struct xpc_openclose_args *args = ch->local_openclose_args; - - args->msg_size = ch->msg_size; - args->local_nentries = ch->local_nentries; - - XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_OPENREQUEST, irq_flags); -} - -static inline void -xpc_IPI_send_openreply(struct xpc_channel *ch, unsigned long *irq_flags) -{ - struct xpc_openclose_args *args = ch->local_openclose_args; - - args->remote_nentries = ch->remote_nentries; - args->local_nentries = ch->local_nentries; - args->local_msgqueue_pa = __pa(ch->local_msgqueue); - - XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_OPENREPLY, irq_flags); -} - -static inline void -xpc_IPI_send_msgrequest(struct xpc_channel *ch) -{ - XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_MSGREQUEST, NULL); -} - -static inline void -xpc_IPI_send_local_msgrequest(struct xpc_channel *ch) -{ - XPC_NOTIFY_IRQ_SEND_LOCAL(ch, XPC_IPI_MSGREQUEST); -} - -/* ->>> this block comment needs to be moved and re-written. - * Memory for XPC's AMO variables is allocated by the MSPEC driver. These - * pages are located in the lowest granule. The lowest granule uses 4k pages - * for cached references and an alternate TLB handler to never provide a - * cacheable mapping for the entire region. This will prevent speculative - * reading of cached copies of our lines from being issued which will cause - * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64 - * AMO variables (based on xp_max_npartitions) for message notification and an - * additional 128 AMO variables (based on XP_NASID_MASK_WORDS) for partition - * activation and 2 AMO variables for partition deactivation. - */ -static inline AMO_t * -xpc_IPI_init(int index) -{ - AMO_t *amo = xpc_vars->amos_page + index; - - (void)xpc_IPI_receive(amo); /* clear AMO variable */ - return amo; -} - -/* - * Check to see if there is any channel activity to/from the specified - * partition. - */ -static inline void -xpc_check_for_channel_activity(struct xpc_partition *part) -{ - u64 IPI_amo; - unsigned long irq_flags; - - IPI_amo = xpc_IPI_receive(part->local_IPI_amo_va); - if (IPI_amo == 0) - return; - - spin_lock_irqsave(&part->IPI_lock, irq_flags); - part->local_IPI_amo |= IPI_amo; - spin_unlock_irqrestore(&part->IPI_lock, irq_flags); - - dev_dbg(xpc_chan, "received IPI from partid=%d, IPI_amo=0x%lx\n", - XPC_PARTID(part), IPI_amo); - - xpc_wakeup_channel_mgr(part); -} - #endif /* _DRIVERS_MISC_SGIXP_XPC_H */ diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index 8081e8155df..26c5e12c122 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -1165,7 +1165,7 @@ xpc_disconnect_callout(struct xpc_channel *ch, enum xp_retval reason) * Wait for a message entry to become available for the specified channel, * but don't wait any longer than 1 jiffy. */ -static enum xp_retval +enum xp_retval xpc_allocate_msg_wait(struct xpc_channel *ch) { enum xp_retval ret; @@ -1191,96 +1191,6 @@ xpc_allocate_msg_wait(struct xpc_channel *ch) return ret; } -/* - * Allocate an entry for a message from the message queue associated with the - * specified channel. - */ -static enum xp_retval -xpc_allocate_msg(struct xpc_channel *ch, u32 flags, - struct xpc_msg **address_of_msg) -{ - struct xpc_msg *msg; - enum xp_retval ret; - s64 put; - - /* this reference will be dropped in xpc_send_msg() */ - xpc_msgqueue_ref(ch); - - if (ch->flags & XPC_C_DISCONNECTING) { - xpc_msgqueue_deref(ch); - return ch->reason; - } - if (!(ch->flags & XPC_C_CONNECTED)) { - xpc_msgqueue_deref(ch); - return xpNotConnected; - } - - /* - * Get the next available message entry from the local message queue. - * If none are available, we'll make sure that we grab the latest - * GP values. - */ - ret = xpTimeout; - - while (1) { - - put = ch->w_local_GP.put; - rmb(); /* guarantee that .put loads before .get */ - if (put - ch->w_remote_GP.get < ch->local_nentries) { - - /* There are available message entries. We need to try - * to secure one for ourselves. We'll do this by trying - * to increment w_local_GP.put as long as someone else - * doesn't beat us to it. If they do, we'll have to - * try again. - */ - if (cmpxchg(&ch->w_local_GP.put, put, put + 1) == put) { - /* we got the entry referenced by put */ - break; - } - continue; /* try again */ - } - - /* - * There aren't any available msg entries at this time. - * - * In waiting for a message entry to become available, - * we set a timeout in case the other side is not - * sending completion IPIs. This lets us fake an IPI - * that will cause the IPI handler to fetch the latest - * GP values as if an IPI was sent by the other side. - */ - if (ret == xpTimeout) - xpc_IPI_send_local_msgrequest(ch); - - if (flags & XPC_NOWAIT) { - xpc_msgqueue_deref(ch); - return xpNoWait; - } - - ret = xpc_allocate_msg_wait(ch); - if (ret != xpInterrupted && ret != xpTimeout) { - xpc_msgqueue_deref(ch); - return ret; - } - } - - /* get the message's address and initialize it */ - msg = (struct xpc_msg *)((u64)ch->local_msgqueue + - (put % ch->local_nentries) * ch->msg_size); - - DBUG_ON(msg->flags != 0); - msg->number = put; - - dev_dbg(xpc_chan, "w_local_GP.put changed to %ld; msg=0x%p, " - "msg_number=%ld, partid=%d, channel=%d\n", put + 1, - (void *)msg, msg->number, ch->partid, ch->number); - - *address_of_msg = msg; - - return xpSuccess; -} - /* * Allocate an entry for a message from the message queue associated with the * specified channel. NOTE that this routine can sleep waiting for a message @@ -1317,144 +1227,6 @@ xpc_initiate_allocate(short partid, int ch_number, u32 flags, void **payload) return ret; } -/* - * Now we actually send the messages that are ready to be sent by advancing - * the local message queue's Put value and then send an IPI to the recipient - * partition. - */ -static void -xpc_send_msgs(struct xpc_channel *ch, s64 initial_put) -{ - struct xpc_msg *msg; - s64 put = initial_put + 1; - int send_IPI = 0; - - while (1) { - - while (1) { - if (put == ch->w_local_GP.put) - break; - - msg = (struct xpc_msg *)((u64)ch->local_msgqueue + - (put % ch->local_nentries) * - ch->msg_size); - - if (!(msg->flags & XPC_M_READY)) - break; - - put++; - } - - if (put == initial_put) { - /* nothing's changed */ - break; - } - - if (cmpxchg_rel(&ch->local_GP->put, initial_put, put) != - initial_put) { - /* someone else beat us to it */ - DBUG_ON(ch->local_GP->put < initial_put); - break; - } - - /* we just set the new value of local_GP->put */ - - dev_dbg(xpc_chan, "local_GP->put changed to %ld, partid=%d, " - "channel=%d\n", put, ch->partid, ch->number); - - send_IPI = 1; - - /* - * We need to ensure that the message referenced by - * local_GP->put is not XPC_M_READY or that local_GP->put - * equals w_local_GP.put, so we'll go have a look. - */ - initial_put = put; - } - - if (send_IPI) - xpc_IPI_send_msgrequest(ch); -} - -/* - * Common code that does the actual sending of the message by advancing the - * local message queue's Put value and sends an IPI to the partition the - * message is being sent to. - */ -static enum xp_retval -xpc_send_msg(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type, - xpc_notify_func func, void *key) -{ - enum xp_retval ret = xpSuccess; - struct xpc_notify *notify = notify; - s64 put, msg_number = msg->number; - - DBUG_ON(notify_type == XPC_N_CALL && func == NULL); - DBUG_ON((((u64)msg - (u64)ch->local_msgqueue) / ch->msg_size) != - msg_number % ch->local_nentries); - DBUG_ON(msg->flags & XPC_M_READY); - - if (ch->flags & XPC_C_DISCONNECTING) { - /* drop the reference grabbed in xpc_allocate_msg() */ - xpc_msgqueue_deref(ch); - return ch->reason; - } - - if (notify_type != 0) { - /* - * Tell the remote side to send an ACK interrupt when the - * message has been delivered. - */ - msg->flags |= XPC_M_INTERRUPT; - - atomic_inc(&ch->n_to_notify); - - notify = &ch->notify_queue[msg_number % ch->local_nentries]; - notify->func = func; - notify->key = key; - notify->type = notify_type; - - /* >>> is a mb() needed here? */ - - if (ch->flags & XPC_C_DISCONNECTING) { - /* - * An error occurred between our last error check and - * this one. We will try to clear the type field from - * the notify entry. If we succeed then - * xpc_disconnect_channel() didn't already process - * the notify entry. - */ - if (cmpxchg(¬ify->type, notify_type, 0) == - notify_type) { - atomic_dec(&ch->n_to_notify); - ret = ch->reason; - } - - /* drop the reference grabbed in xpc_allocate_msg() */ - xpc_msgqueue_deref(ch); - return ret; - } - } - - msg->flags |= XPC_M_READY; - - /* - * The preceding store of msg->flags must occur before the following - * load of ch->local_GP->put. - */ - mb(); - - /* see if the message is next in line to be sent, if so send it */ - - put = ch->local_GP->put; - if (put == msg_number) - xpc_send_msgs(ch, put); - - /* drop the reference grabbed in xpc_allocate_msg() */ - xpc_msgqueue_deref(ch); - return ret; -} - /* * Send a message previously allocated using xpc_initiate_allocate() on the * specified channel connected to the specified partition. @@ -1585,66 +1357,6 @@ xpc_deliver_msg(struct xpc_channel *ch) } } -/* - * Now we actually acknowledge the messages that have been delivered and ack'd - * by advancing the cached remote message queue's Get value and if requested - * send an IPI to the message sender's partition. - */ -static void -xpc_acknowledge_msgs(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) -{ - struct xpc_msg *msg; - s64 get = initial_get + 1; - int send_IPI = 0; - - while (1) { - - while (1) { - if (get == ch->w_local_GP.get) - break; - - msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + - (get % ch->remote_nentries) * - ch->msg_size); - - if (!(msg->flags & XPC_M_DONE)) - break; - - msg_flags |= msg->flags; - get++; - } - - if (get == initial_get) { - /* nothing's changed */ - break; - } - - if (cmpxchg_rel(&ch->local_GP->get, initial_get, get) != - initial_get) { - /* someone else beat us to it */ - DBUG_ON(ch->local_GP->get <= initial_get); - break; - } - - /* we just set the new value of local_GP->get */ - - dev_dbg(xpc_chan, "local_GP->get changed to %ld, partid=%d, " - "channel=%d\n", get, ch->partid, ch->number); - - send_IPI = (msg_flags & XPC_M_INTERRUPT); - - /* - * We need to ensure that the message referenced by - * local_GP->get is not XPC_M_DONE or that local_GP->get - * equals w_local_GP.get, so we'll go have a look. - */ - initial_get = get; - } - - if (send_IPI) - xpc_IPI_send_msgrequest(ch); -} - /* * Acknowledge receipt of a delivered message. * @@ -1668,35 +1380,12 @@ xpc_initiate_received(short partid, int ch_number, void *payload) struct xpc_partition *part = &xpc_partitions[partid]; struct xpc_channel *ch; struct xpc_msg *msg = XPC_MSG_ADDRESS(payload); - s64 get, msg_number = msg->number; DBUG_ON(partid < 0 || partid >= xp_max_npartitions); DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); ch = &part->channels[ch_number]; - - dev_dbg(xpc_chan, "msg=0x%p, msg_number=%ld, partid=%d, channel=%d\n", - (void *)msg, msg_number, ch->partid, ch->number); - - DBUG_ON((((u64)msg - (u64)ch->remote_msgqueue) / ch->msg_size) != - msg_number % ch->remote_nentries); - DBUG_ON(msg->flags & XPC_M_DONE); - - msg->flags |= XPC_M_DONE; - - /* - * The preceding store of msg->flags must occur before the following - * load of ch->local_GP->get. - */ - mb(); - - /* - * See if this message is next in line to be acknowledged as having - * been delivered. - */ - get = ch->local_GP->get; - if (get == msg_number) - xpc_acknowledge_msgs(ch, get, msg->flags); + xpc_received_msg(ch, msg); /* the call to xpc_msgqueue_ref() was done by xpc_deliver_msg() */ xpc_msgqueue_deref(ch); diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index be3a4853930..10dac3652b2 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -148,12 +148,14 @@ static struct ctl_table_header *xpc_sysctl; int xpc_disengage_request_timedout; /* #of IRQs received */ -static atomic_t xpc_act_IRQ_rcvd; +atomic_t xpc_act_IRQ_rcvd; /* IRQ handler notifies this wait queue on receipt of an IRQ */ -static DECLARE_WAIT_QUEUE_HEAD(xpc_act_IRQ_wq); +DECLARE_WAIT_QUEUE_HEAD(xpc_act_IRQ_wq); static unsigned long xpc_hb_check_timeout; +static struct timer_list xpc_hb_timer; +void *xpc_heartbeating_to_mask; /* notification that the xpc_hb_checker thread has exited */ static DECLARE_COMPLETION(xpc_hb_checker_exited); @@ -161,8 +163,6 @@ static DECLARE_COMPLETION(xpc_hb_checker_exited); /* notification that the xpc_discovery thread has exited */ static DECLARE_COMPLETION(xpc_discovery_exited); -static struct timer_list xpc_hb_timer; - static void xpc_kthread_waitmsgs(struct xpc_partition *, struct xpc_channel *); static int xpc_system_reboot(struct notifier_block *, unsigned long, void *); @@ -176,12 +176,54 @@ static struct notifier_block xpc_die_notifier = { }; enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *rp); +void (*xpc_heartbeat_init) (void); +void (*xpc_heartbeat_exit) (void); +void (*xpc_increment_heartbeat) (void); +void (*xpc_offline_heartbeat) (void); +void (*xpc_online_heartbeat) (void); +void (*xpc_check_remote_hb) (void); + enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *part); u64 (*xpc_get_IPI_flags) (struct xpc_partition *part); struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *ch); + +void (*xpc_initiate_partition_activation) (struct xpc_rsvd_page *remote_rp, + u64 remote_rp_pa, int nasid); + +void (*xpc_process_act_IRQ_rcvd) (int n_IRQs_expected); enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *part); void (*xpc_teardown_infrastructure) (struct xpc_partition *part); +void (*xpc_mark_partition_engaged) (struct xpc_partition *part); +void (*xpc_mark_partition_disengaged) (struct xpc_partition *part); +void (*xpc_request_partition_disengage) (struct xpc_partition *part); +void (*xpc_cancel_partition_disengage_request) (struct xpc_partition *part); +u64 (*xpc_partition_engaged) (u64 partid_mask); +u64 (*xpc_partition_disengage_requested) (u64 partid_mask); +void (*xpc_clear_partition_engaged) (u64 partid_mask); +void (*xpc_clear_partition_disengage_request) (u64 partid_mask); + +void (*xpc_IPI_send_local_activate) (int from_nasid); +void (*xpc_IPI_send_activated) (struct xpc_partition *part); +void (*xpc_IPI_send_local_reactivate) (int from_nasid); +void (*xpc_IPI_send_disengage) (struct xpc_partition *part); + +void (*xpc_IPI_send_closerequest) (struct xpc_channel *ch, + unsigned long *irq_flags); +void (*xpc_IPI_send_closereply) (struct xpc_channel *ch, + unsigned long *irq_flags); +void (*xpc_IPI_send_openrequest) (struct xpc_channel *ch, + unsigned long *irq_flags); +void (*xpc_IPI_send_openreply) (struct xpc_channel *ch, + unsigned long *irq_flags); + +enum xp_retval (*xpc_allocate_msg) (struct xpc_channel *ch, u32 flags, + struct xpc_msg **address_of_msg); + +enum xp_retval (*xpc_send_msg) (struct xpc_channel *ch, struct xpc_msg *msg, + u8 notify_type, xpc_notify_func func, + void *key); +void (*xpc_received_msg) (struct xpc_channel *ch, struct xpc_msg *msg); /* * Timer function to enforce the timelimit on the partition disengage request. @@ -218,7 +260,7 @@ xpc_act_IRQ_handler(int irq, void *dev_id) static void xpc_hb_beater(unsigned long dummy) { - xpc_vars->heartbeat++; + xpc_increment_heartbeat(); if (time_after_eq(jiffies, xpc_hb_check_timeout)) wake_up_interruptible(&xpc_act_IRQ_wq); @@ -227,6 +269,22 @@ xpc_hb_beater(unsigned long dummy) add_timer(&xpc_hb_timer); } +static void +xpc_start_hb_beater(void) +{ + xpc_heartbeat_init(); + init_timer(&xpc_hb_timer); + xpc_hb_timer.function = xpc_hb_beater; + xpc_hb_beater(0); +} + +static void +xpc_stop_hb_beater(void) +{ + del_timer_sync(&xpc_hb_timer); + xpc_heartbeat_exit(); +} + /* * This thread is responsible for nearly all of the partition * activation/deactivation. @@ -244,7 +302,7 @@ xpc_hb_checker(void *ignore) /* set our heartbeating to other partitions into motion */ xpc_hb_check_timeout = jiffies + (xpc_hb_check_interval * HZ); - xpc_hb_beater(0); + xpc_start_hb_beater(); while (!xpc_exiting) { @@ -274,11 +332,8 @@ xpc_hb_checker(void *ignore) dev_dbg(xpc_part, "found an IRQ to process; will be " "resetting xpc_hb_check_timeout\n"); - last_IRQ_count += xpc_identify_act_IRQ_sender(); - if (last_IRQ_count < new_IRQ_count) { - /* retry once to help avoid missing AMO */ - (void)xpc_identify_act_IRQ_sender(); - } + xpc_process_act_IRQ_rcvd(new_IRQ_count - + last_IRQ_count); last_IRQ_count = new_IRQ_count; xpc_hb_check_timeout = jiffies + @@ -294,6 +349,8 @@ xpc_hb_checker(void *ignore) xpc_exiting)); } + xpc_stop_hb_beater(); + dev_dbg(xpc_part, "heartbeat checker is exiting\n"); /* mark this thread as having exited */ @@ -401,31 +458,7 @@ xpc_activating(void *__partid) dev_dbg(xpc_part, "activating partition %d\n", partid); - /* - * Register the remote partition's AMOs with SAL so it can handle - * and cleanup errors within that address range should the remote - * partition go down. We don't unregister this range because it is - * difficult to tell when outstanding writes to the remote partition - * are finished and thus when it is safe to unregister. This should - * not result in wasted space in the SAL xp_addr_region table because - * we should get the same page for remote_amos_page_pa after module - * reloads and system reboots. - */ - if (sn_register_xp_addr_region(part->remote_amos_page_pa, - PAGE_SIZE, 1) < 0) { - dev_warn(xpc_part, "xpc_activating(%d) failed to register " - "xp_addr region\n", partid); - - spin_lock_irqsave(&part->act_lock, irq_flags); - part->act_state = XPC_P_INACTIVE; - XPC_SET_REASON(part, xpPhysAddrRegFailed, __LINE__); - spin_unlock_irqrestore(&part->act_lock, irq_flags); - part->remote_rp_pa = 0; - return 0; - } - - xpc_allow_hb(partid, xpc_vars); - xpc_IPI_send_activated(part); + xpc_allow_hb(partid); if (xpc_setup_infrastructure(part) == xpSuccess) { (void)xpc_part_ref(part); /* this will always succeed */ @@ -440,12 +473,12 @@ xpc_activating(void *__partid) xpc_teardown_infrastructure(part); } - xpc_disallow_hb(partid, xpc_vars); + xpc_disallow_hb(partid); xpc_mark_partition_inactive(part); if (part->reason == xpReactivating) { /* interrupting ourselves results in activating partition */ - xpc_IPI_send_reactivate(part); + xpc_IPI_send_local_reactivate(part->reactivate_nasid); } return 0; @@ -477,6 +510,32 @@ xpc_activate_partition(struct xpc_partition *part) } } +/* + * Check to see if there is any channel activity to/from the specified + * partition. + */ +static void +xpc_check_for_channel_activity(struct xpc_partition *part) +{ + u64 IPI_amo; + unsigned long irq_flags; + +/* this needs to be uncommented, but I'm thinking this function and the */ +/* ones that call it need to be moved into xpc_sn2.c... */ + IPI_amo = 0; /* = xpc_IPI_receive(part->local_IPI_amo_va); */ + if (IPI_amo == 0) + return; + + spin_lock_irqsave(&part->IPI_lock, irq_flags); + part->local_IPI_amo |= IPI_amo; + spin_unlock_irqrestore(&part->IPI_lock, irq_flags); + + dev_dbg(xpc_chan, "received IPI from partid=%d, IPI_amo=0x%lx\n", + XPC_PARTID(part), IPI_amo); + + xpc_wakeup_channel_mgr(part); +} + /* * Handle the receipt of a SGI_XPC_NOTIFY IRQ by seeing whether the specified * partition actually sent it. Since SGI_XPC_NOTIFY IRQs may be shared by more @@ -902,14 +961,11 @@ xpc_do_exit(enum xp_retval reason) } while (1); DBUG_ON(xpc_partition_engaged(-1UL)); + DBUG_ON(xpc_any_hbs_allowed() != 0); /* indicate to others that our reserved page is uninitialized */ xpc_rsvd_page->stamp = ZERO_STAMP; - /* now it's time to eliminate our heartbeat */ - del_timer_sync(&xpc_hb_timer); - DBUG_ON(xpc_vars->heartbeating_to_mask != 0); - if (reason == xpUnloading) { (void)unregister_die_notifier(&xpc_die_notifier); (void)unregister_reboot_notifier(&xpc_reboot_notifier); @@ -968,7 +1024,7 @@ xpc_die_disengage(void) /* keep xpc_hb_checker thread from doing anything (just in case) */ xpc_exiting = 1; - xpc_vars->heartbeating_to_mask = 0; /* indicate we're deactivated */ + xpc_disallow_all_hbs(); /*indicate we're deactivated */ for (partid = 0; partid < xp_max_npartitions; partid++) { part = &xpc_partitions[partid]; @@ -1054,8 +1110,7 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) /* fall through */ case DIE_MCA_MONARCH_ENTER: case DIE_INIT_MONARCH_ENTER: - xpc_vars->heartbeat++; - xpc_vars->heartbeat_offline = 1; + xpc_offline_heartbeat(); break; case DIE_KDEBUG_LEAVE: @@ -1066,8 +1121,7 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) /* fall through */ case DIE_MCA_MONARCH_LEAVE: case DIE_INIT_MONARCH_LEAVE: - xpc_vars->heartbeat++; - xpc_vars->heartbeat_offline = 0; + xpc_online_heartbeat(); break; } @@ -1202,9 +1256,6 @@ xpc_init(void) if (ret != 0) dev_warn(xpc_part, "can't register die notifier\n"); - init_timer(&xpc_hb_timer); - xpc_hb_timer.function = xpc_hb_beater; - /* * The real work-horse behind xpc. This processes incoming * interrupts and monitors remote heartbeats. @@ -1246,7 +1297,6 @@ out_4: /* indicate to others that our reserved page is uninitialized */ xpc_rsvd_page->stamp = ZERO_STAMP; - del_timer_sync(&xpc_hb_timer); (void)unregister_die_notifier(&xpc_die_notifier); (void)unregister_reboot_notifier(&xpc_reboot_notifier); out_3: diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index be5b7547dab..4e14effdedd 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -42,7 +42,7 @@ u64 xpc_prot_vec[MAX_NUMNODES]; /* this partition's reserved page pointers */ struct xpc_rsvd_page *xpc_rsvd_page; static u64 *xpc_part_nasids; -static u64 *xpc_mach_nasids; +u64 *xpc_mach_nasids; /* >>> next two variables should be 'xpc_' if they remain here */ static int xp_sizeof_nasid_mask; /* actual size in bytes of nasid mask */ @@ -317,62 +317,6 @@ xpc_restrict_IPI_ops(void) } } -/* - * At periodic intervals, scan through all active partitions and ensure - * their heartbeat is still active. If not, the partition is deactivated. - */ -void -xpc_check_remote_hb(void) -{ - struct xpc_vars *remote_vars; - struct xpc_partition *part; - short partid; - enum xp_retval ret; - - remote_vars = (struct xpc_vars *)xpc_remote_copy_buffer; - - for (partid = 0; partid < xp_max_npartitions; partid++) { - - if (xpc_exiting) - break; - - if (partid == sn_partition_id) - continue; - - part = &xpc_partitions[partid]; - - if (part->act_state == XPC_P_INACTIVE || - part->act_state == XPC_P_DEACTIVATING) { - continue; - } - - /* pull the remote_hb cache line */ - ret = xp_remote_memcpy(remote_vars, - (void *)part->remote_vars_pa, - XPC_RP_VARS_SIZE); - if (ret != xpSuccess) { - XPC_DEACTIVATE_PARTITION(part, ret); - continue; - } - - dev_dbg(xpc_part, "partid = %d, heartbeat = %ld, last_heartbeat" - " = %ld, heartbeat_offline = %ld, HB_mask = 0x%lx\n", - partid, remote_vars->heartbeat, part->last_heartbeat, - remote_vars->heartbeat_offline, - remote_vars->heartbeating_to_mask); - - if (((remote_vars->heartbeat == part->last_heartbeat) && - (remote_vars->heartbeat_offline == 0)) || - !xpc_hb_allowed(sn_partition_id, remote_vars)) { - - XPC_DEACTIVATE_PARTITION(part, xpNoHeartbeat); - continue; - } - - part->last_heartbeat = remote_vars->heartbeat; - } -} - /* * Get a copy of a portion of the remote partition's rsvd page. * @@ -380,7 +324,7 @@ xpc_check_remote_hb(void) * is large enough to contain a copy of their reserved page header and * part_nasids mask. */ -static enum xp_retval +enum xp_retval xpc_get_remote_rp(int nasid, u64 *discovered_nasids, struct xpc_rsvd_page *remote_rp, u64 *remote_rp_pa) { @@ -431,322 +375,6 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, return xpSuccess; } -/* - * Get a copy of the remote partition's XPC variables from the reserved page. - * - * remote_vars points to a buffer that is cacheline aligned for BTE copies and - * assumed to be of size XPC_RP_VARS_SIZE. - */ -static enum xp_retval -xpc_get_remote_vars(u64 remote_vars_pa, struct xpc_vars *remote_vars) -{ - enum xp_retval ret; - - if (remote_vars_pa == 0) - return xpVarsNotSet; - - /* pull over the cross partition variables */ - ret = xp_remote_memcpy(remote_vars, (void *)remote_vars_pa, - XPC_RP_VARS_SIZE); - if (ret != xpSuccess) - return ret; - - if (XPC_VERSION_MAJOR(remote_vars->version) != - XPC_VERSION_MAJOR(XPC_V_VERSION)) { - return xpBadVersion; - } - - return xpSuccess; -} - -/* - * Update the remote partition's info. - */ -static void -xpc_update_partition_info(struct xpc_partition *part, u8 remote_rp_version, - struct timespec *remote_rp_stamp, u64 remote_rp_pa, - u64 remote_vars_pa, struct xpc_vars *remote_vars) -{ - part->remote_rp_version = remote_rp_version; - dev_dbg(xpc_part, " remote_rp_version = 0x%016x\n", - part->remote_rp_version); - - part->remote_rp_stamp = *remote_rp_stamp; - dev_dbg(xpc_part, " remote_rp_stamp (tv_sec = 0x%lx tv_nsec = 0x%lx\n", - part->remote_rp_stamp.tv_sec, part->remote_rp_stamp.tv_nsec); - - part->remote_rp_pa = remote_rp_pa; - dev_dbg(xpc_part, " remote_rp_pa = 0x%016lx\n", part->remote_rp_pa); - - part->remote_vars_pa = remote_vars_pa; - dev_dbg(xpc_part, " remote_vars_pa = 0x%016lx\n", - part->remote_vars_pa); - - part->last_heartbeat = remote_vars->heartbeat; - dev_dbg(xpc_part, " last_heartbeat = 0x%016lx\n", - part->last_heartbeat); - -/* >>> remote_vars_part_pa and vars_part_pa are sn2 only!!! */ - part->remote_vars_part_pa = remote_vars->vars_part_pa; - dev_dbg(xpc_part, " remote_vars_part_pa = 0x%016lx\n", - part->remote_vars_part_pa); - - part->remote_act_nasid = remote_vars->act_nasid; - dev_dbg(xpc_part, " remote_act_nasid = 0x%x\n", - part->remote_act_nasid); - - part->remote_act_phys_cpuid = remote_vars->act_phys_cpuid; - dev_dbg(xpc_part, " remote_act_phys_cpuid = 0x%x\n", - part->remote_act_phys_cpuid); - - part->remote_amos_page_pa = remote_vars->amos_page_pa; - dev_dbg(xpc_part, " remote_amos_page_pa = 0x%lx\n", - part->remote_amos_page_pa); - - part->remote_vars_version = remote_vars->version; - dev_dbg(xpc_part, " remote_vars_version = 0x%x\n", - part->remote_vars_version); -} - -/* - * Prior code has determined the nasid which generated an IPI. Inspect - * that nasid to determine if its partition needs to be activated or - * deactivated. - * - * A partition is consider "awaiting activation" if our partition - * flags indicate it is not active and it has a heartbeat. A - * partition is considered "awaiting deactivation" if our partition - * flags indicate it is active but it has no heartbeat or it is not - * sending its heartbeat to us. - * - * To determine the heartbeat, the remote nasid must have a properly - * initialized reserved page. - */ -static void -xpc_identify_act_IRQ_req(int nasid) -{ - struct xpc_rsvd_page *remote_rp; - struct xpc_vars *remote_vars; - u64 remote_rp_pa; - u64 remote_vars_pa; - int remote_rp_version; - int reactivate = 0; - int stamp_diff; - struct timespec remote_rp_stamp = { 0, 0 }; /*>>> ZERO_STAMP */ - short partid; - struct xpc_partition *part; - enum xp_retval ret; - - /* pull over the reserved page structure */ - - remote_rp = (struct xpc_rsvd_page *)xpc_remote_copy_buffer; - - ret = xpc_get_remote_rp(nasid, NULL, remote_rp, &remote_rp_pa); - if (ret != xpSuccess) { - dev_warn(xpc_part, "unable to get reserved page from nasid %d, " - "which sent interrupt, reason=%d\n", nasid, ret); - return; - } - - remote_vars_pa = remote_rp->sn.vars_pa; - remote_rp_version = remote_rp->version; - if (XPC_SUPPORTS_RP_STAMP(remote_rp_version)) - remote_rp_stamp = remote_rp->stamp; - - partid = remote_rp->SAL_partid; - part = &xpc_partitions[partid]; - - /* pull over the cross partition variables */ - - remote_vars = (struct xpc_vars *)xpc_remote_copy_buffer; - - ret = xpc_get_remote_vars(remote_vars_pa, remote_vars); - if (ret != xpSuccess) { - - dev_warn(xpc_part, "unable to get XPC variables from nasid %d, " - "which sent interrupt, reason=%d\n", nasid, ret); - - XPC_DEACTIVATE_PARTITION(part, ret); - return; - } - - part->act_IRQ_rcvd++; - - dev_dbg(xpc_part, "partid for nasid %d is %d; IRQs = %d; HB = " - "%ld:0x%lx\n", (int)nasid, (int)partid, part->act_IRQ_rcvd, - remote_vars->heartbeat, remote_vars->heartbeating_to_mask); - - if (xpc_partition_disengaged(part) && - part->act_state == XPC_P_INACTIVE) { - - xpc_update_partition_info(part, remote_rp_version, - &remote_rp_stamp, remote_rp_pa, - remote_vars_pa, remote_vars); - - if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) { - if (xpc_partition_disengage_requested(1UL << partid)) { - /* - * Other side is waiting on us to disengage, - * even though we already have. - */ - return; - } - } else { - /* other side doesn't support disengage requests */ - xpc_clear_partition_disengage_request(1UL << partid); - } - - xpc_activate_partition(part); - return; - } - - DBUG_ON(part->remote_rp_version == 0); - DBUG_ON(part->remote_vars_version == 0); - - if (!XPC_SUPPORTS_RP_STAMP(part->remote_rp_version)) { - DBUG_ON(XPC_SUPPORTS_DISENGAGE_REQUEST(part-> - remote_vars_version)); - - if (!XPC_SUPPORTS_RP_STAMP(remote_rp_version)) { - DBUG_ON(XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars-> - version)); - /* see if the other side rebooted */ - if (part->remote_amos_page_pa == - remote_vars->amos_page_pa && - xpc_hb_allowed(sn_partition_id, remote_vars)) { - /* doesn't look that way, so ignore the IPI */ - return; - } - } - - /* - * Other side rebooted and previous XPC didn't support the - * disengage request, so we don't need to do anything special. - */ - - xpc_update_partition_info(part, remote_rp_version, - &remote_rp_stamp, remote_rp_pa, - remote_vars_pa, remote_vars); - part->reactivate_nasid = nasid; - XPC_DEACTIVATE_PARTITION(part, xpReactivating); - return; - } - - DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)); - - if (!XPC_SUPPORTS_RP_STAMP(remote_rp_version)) { - DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->version)); - - /* - * Other side rebooted and previous XPC did support the - * disengage request, but the new one doesn't. - */ - - xpc_clear_partition_engaged(1UL << partid); - xpc_clear_partition_disengage_request(1UL << partid); - - xpc_update_partition_info(part, remote_rp_version, - &remote_rp_stamp, remote_rp_pa, - remote_vars_pa, remote_vars); - reactivate = 1; - - } else { - DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->version)); - - stamp_diff = xpc_compare_stamps(&part->remote_rp_stamp, - &remote_rp_stamp); - if (stamp_diff != 0) { - DBUG_ON(stamp_diff >= 0); - - /* - * Other side rebooted and the previous XPC did support - * the disengage request, as does the new one. - */ - - DBUG_ON(xpc_partition_engaged(1UL << partid)); - DBUG_ON(xpc_partition_disengage_requested(1UL << - partid)); - - xpc_update_partition_info(part, remote_rp_version, - &remote_rp_stamp, - remote_rp_pa, remote_vars_pa, - remote_vars); - reactivate = 1; - } - } - - if (part->disengage_request_timeout > 0 && - !xpc_partition_disengaged(part)) { - /* still waiting on other side to disengage from us */ - return; - } - - if (reactivate) { - part->reactivate_nasid = nasid; - XPC_DEACTIVATE_PARTITION(part, xpReactivating); - - } else if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version) && - xpc_partition_disengage_requested(1UL << partid)) { - XPC_DEACTIVATE_PARTITION(part, xpOtherGoingDown); - } -} - -/* - * Loop through the activation AMO variables and process any bits - * which are set. Each bit indicates a nasid sending a partition - * activation or deactivation request. - * - * Return #of IRQs detected. - */ -int -xpc_identify_act_IRQ_sender(void) -{ - int word, bit; - u64 nasid_mask; - u64 nasid; /* remote nasid */ - int n_IRQs_detected = 0; - AMO_t *act_amos; - - act_amos = xpc_vars->amos_page + XPC_ACTIVATE_IRQ_AMOS; - - /* scan through act AMO variable looking for non-zero entries */ - for (word = 0; word < xp_nasid_mask_words; word++) { - - if (xpc_exiting) - break; - - nasid_mask = xpc_IPI_receive(&act_amos[word]); - if (nasid_mask == 0) { - /* no IRQs from nasids in this variable */ - continue; - } - - dev_dbg(xpc_part, "AMO[%d] gave back 0x%lx\n", word, - nasid_mask); - - /* - * If this nasid has been added to the machine since - * our partition was reset, this will retain the - * remote nasid in our reserved pages machine mask. - * This is used in the event of module reload. - */ - xpc_mach_nasids[word] |= nasid_mask; - - /* locate the nasid(s) which sent interrupts */ - - for (bit = 0; bit < (8 * sizeof(u64)); bit++) { - if (nasid_mask & (1UL << bit)) { - n_IRQs_detected++; - nasid = XPC_NASID_FROM_W_B(word, bit); - dev_dbg(xpc_part, "interrupt from nasid %ld\n", - nasid); - xpc_identify_act_IRQ_req(nasid); - } - } - } - return n_IRQs_detected; -} - /* * See if the other side has responded to a partition disengage request * from us. @@ -836,7 +464,7 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part, spin_unlock_irqrestore(&part->act_lock, irq_flags); if (reason == xpReactivating) { /* we interrupt ourselves to reactivate partition */ - xpc_IPI_send_reactivate(part); + xpc_IPI_send_local_reactivate(part->reactivate_nasid); } return; } @@ -903,16 +531,12 @@ xpc_discovery(void) { void *remote_rp_base; struct xpc_rsvd_page *remote_rp; - struct xpc_vars *remote_vars; u64 remote_rp_pa; - u64 remote_vars_pa; int region; int region_size; int max_regions; int nasid; struct xpc_rsvd_page *rp; - short partid; - struct xpc_partition *part; u64 *discovered_nasids; enum xp_retval ret; @@ -922,8 +546,6 @@ xpc_discovery(void) if (remote_rp == NULL) return; - remote_vars = (struct xpc_vars *)remote_rp; - discovered_nasids = kzalloc(sizeof(u64) * xp_nasid_mask_words, GFP_KERNEL); if (discovered_nasids == NULL) { @@ -988,7 +610,7 @@ xpc_discovery(void) continue; } - /* pull over the reserved page structure */ + /* pull over the rsvd page header & part_nasids mask */ ret = xpc_get_remote_rp(nasid, discovered_nasids, remote_rp, &remote_rp_pa); @@ -1003,72 +625,8 @@ xpc_discovery(void) continue; } - remote_vars_pa = remote_rp->sn.vars_pa; - - partid = remote_rp->SAL_partid; - part = &xpc_partitions[partid]; - - /* pull over the cross partition variables */ - - ret = xpc_get_remote_vars(remote_vars_pa, remote_vars); - if (ret != xpSuccess) { - dev_dbg(xpc_part, "unable to get XPC variables " - "from nasid %d, reason=%d\n", nasid, - ret); - - XPC_DEACTIVATE_PARTITION(part, ret); - continue; - } - - if (part->act_state != XPC_P_INACTIVE) { - dev_dbg(xpc_part, "partition %d on nasid %d is " - "already activating\n", partid, nasid); - break; - } - - /* - * Register the remote partition's AMOs with SAL so it - * can handle and cleanup errors within that address - * range should the remote partition go down. We don't - * unregister this range because it is difficult to - * tell when outstanding writes to the remote partition - * are finished and thus when it is thus safe to - * unregister. This should not result in wasted space - * in the SAL xp_addr_region table because we should - * get the same page for remote_act_amos_pa after - * module reloads and system reboots. - */ - if (sn_register_xp_addr_region - (remote_vars->amos_page_pa, PAGE_SIZE, 1) < 0) { - dev_dbg(xpc_part, - "partition %d failed to " - "register xp_addr region 0x%016lx\n", - partid, remote_vars->amos_page_pa); - - XPC_SET_REASON(part, xpPhysAddrRegFailed, - __LINE__); - break; - } - - /* - * The remote nasid is valid and available. - * Send an interrupt to that nasid to notify - * it that we are ready to begin activation. - */ - dev_dbg(xpc_part, "sending an interrupt to AMO 0x%lx, " - "nasid %d, phys_cpuid 0x%x\n", - remote_vars->amos_page_pa, - remote_vars->act_nasid, - remote_vars->act_phys_cpuid); - - if (XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars-> - version)) { - part->remote_amos_page_pa = - remote_vars->amos_page_pa; - xpc_mark_partition_disengaged(part); - xpc_cancel_partition_disengage_request(part); - } - xpc_IPI_send_activate(remote_vars); + xpc_initiate_partition_activation(remote_rp, + remote_rp_pa, nasid); } } diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index ee28e231dc4..89c0bb9a27f 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -19,9 +19,370 @@ #include #include "xpc.h" -struct xpc_vars *xpc_vars; +static struct xpc_vars_sn2 *xpc_vars; /* >>> Add _sn2 suffix? */ static struct xpc_vars_part_sn2 *xpc_vars_part; /* >>> Add _sn2 suffix? */ +/* + * The following set of macros and functions are used for the sending and + * receiving of IPIs (also known as IRQs). There are two flavors of IPIs, + * one that is associated with partition activity (SGI_XPC_ACTIVATE) and + * the other that is associated with channel activity (SGI_XPC_NOTIFY). + */ + +static u64 +xpc_IPI_receive_sn2(AMO_t *amo) +{ + return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_CLEAR); +} + +static enum xp_retval +xpc_IPI_send_sn2(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector) +{ + int ret = 0; + unsigned long irq_flags; + + local_irq_save(irq_flags); + + FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, flag); + sn_send_IPI_phys(nasid, phys_cpuid, vector, 0); + + /* + * We must always use the nofault function regardless of whether we + * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we + * didn't, we'd never know that the other partition is down and would + * keep sending IPIs and AMOs to it until the heartbeat times out. + */ + ret = xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->variable), + xp_nofault_PIOR_target)); + + local_irq_restore(irq_flags); + + return ((ret == 0) ? xpSuccess : xpPioReadError); +} + +static AMO_t * +xpc_IPI_init_sn2(int index) +{ + AMO_t *amo = xpc_vars->amos_page + index; + + (void)xpc_IPI_receive_sn2(amo); /* clear AMO variable */ + return amo; +} + +/* + * IPIs associated with SGI_XPC_ACTIVATE IRQ. + */ + +/* + * Flag the appropriate AMO variable and send an IPI to the specified node. + */ +static void +xpc_activate_IRQ_send_sn2(u64 amos_page_pa, int from_nasid, int to_nasid, + int to_phys_cpuid) +{ + int w_index = XPC_NASID_W_INDEX(from_nasid); + int b_index = XPC_NASID_B_INDEX(from_nasid); + AMO_t *amos = (AMO_t *)__va(amos_page_pa + + (XPC_ACTIVATE_IRQ_AMOS * sizeof(AMO_t))); + + (void)xpc_IPI_send_sn2(&amos[w_index], (1UL << b_index), to_nasid, + to_phys_cpuid, SGI_XPC_ACTIVATE); +} + +static void +xpc_activate_IRQ_send_local_sn2(int from_nasid) +{ + int w_index = XPC_NASID_W_INDEX(from_nasid); + int b_index = XPC_NASID_B_INDEX(from_nasid); + AMO_t *amos = (AMO_t *)__va(xpc_vars->amos_page_pa + + (XPC_ACTIVATE_IRQ_AMOS * sizeof(AMO_t))); + + /* fake the sending and receipt of an activate IRQ from remote nasid */ + FETCHOP_STORE_OP(TO_AMO((u64)&amos[w_index].variable), FETCHOP_OR, + (1UL << b_index)); + atomic_inc(&xpc_act_IRQ_rcvd); + wake_up_interruptible(&xpc_act_IRQ_wq); +} + +static void +xpc_IPI_send_local_activate_sn2(int from_nasid) +{ + xpc_activate_IRQ_send_local_sn2(from_nasid); +} + +static void +xpc_IPI_send_activated_sn2(struct xpc_partition *part) +{ + xpc_activate_IRQ_send_sn2(part->remote_amos_page_pa, + cnodeid_to_nasid(0), part->remote_act_nasid, + part->remote_act_phys_cpuid); +} + +static void +xpc_IPI_send_local_reactivate_sn2(int from_nasid) +{ + xpc_activate_IRQ_send_local_sn2(from_nasid); +} + +static void +xpc_IPI_send_disengage_sn2(struct xpc_partition *part) +{ + xpc_activate_IRQ_send_sn2(part->remote_amos_page_pa, + cnodeid_to_nasid(0), part->remote_act_nasid, + part->remote_act_phys_cpuid); +} + +/* + * IPIs associated with SGI_XPC_NOTIFY IRQ. + */ + +/* + * Send an IPI to the remote partition that is associated with the + * specified channel. + */ +static void +xpc_notify_IRQ_send_sn2(struct xpc_channel *ch, u8 ipi_flag, + char *ipi_flag_string, unsigned long *irq_flags) +{ + struct xpc_partition *part = &xpc_partitions[ch->partid]; + enum xp_retval ret; + + if (likely(part->act_state != XPC_P_DEACTIVATING)) { + ret = xpc_IPI_send_sn2(part->remote_IPI_amo_va, + (u64)ipi_flag << (ch->number * 8), + part->remote_IPI_nasid, + part->remote_IPI_phys_cpuid, + SGI_XPC_NOTIFY); + dev_dbg(xpc_chan, "%s sent to partid=%d, channel=%d, ret=%d\n", + ipi_flag_string, ch->partid, ch->number, ret); + if (unlikely(ret != xpSuccess)) { + if (irq_flags != NULL) + spin_unlock_irqrestore(&ch->lock, *irq_flags); + XPC_DEACTIVATE_PARTITION(part, ret); + if (irq_flags != NULL) + spin_lock_irqsave(&ch->lock, *irq_flags); + } + } +} + +#define XPC_NOTIFY_IRQ_SEND_SN2(_ch, _ipi_f, _irq_f) \ + xpc_notify_IRQ_send_sn2(_ch, _ipi_f, #_ipi_f, _irq_f) + +/* + * Make it look like the remote partition, which is associated with the + * specified channel, sent us an IPI. This faked IPI will be handled + * by xpc_dropped_IPI_check(). + */ +static void +xpc_notify_IRQ_send_local_sn2(struct xpc_channel *ch, u8 ipi_flag, + char *ipi_flag_string) +{ + struct xpc_partition *part = &xpc_partitions[ch->partid]; + + FETCHOP_STORE_OP(TO_AMO((u64)&part->local_IPI_amo_va->variable), + FETCHOP_OR, ((u64)ipi_flag << (ch->number * 8))); + dev_dbg(xpc_chan, "%s sent local from partid=%d, channel=%d\n", + ipi_flag_string, ch->partid, ch->number); +} + +#define XPC_NOTIFY_IRQ_SEND_LOCAL_SN2(_ch, _ipi_f) \ + xpc_notify_IRQ_send_local_sn2(_ch, _ipi_f, #_ipi_f) + +static void +xpc_IPI_send_closerequest_sn2(struct xpc_channel *ch, unsigned long *irq_flags) +{ + struct xpc_openclose_args *args = ch->local_openclose_args; + + args->reason = ch->reason; + XPC_NOTIFY_IRQ_SEND_SN2(ch, XPC_IPI_CLOSEREQUEST, irq_flags); +} + +static void +xpc_IPI_send_closereply_sn2(struct xpc_channel *ch, unsigned long *irq_flags) +{ + XPC_NOTIFY_IRQ_SEND_SN2(ch, XPC_IPI_CLOSEREPLY, irq_flags); +} + +static void +xpc_IPI_send_openrequest_sn2(struct xpc_channel *ch, unsigned long *irq_flags) +{ + struct xpc_openclose_args *args = ch->local_openclose_args; + + args->msg_size = ch->msg_size; + args->local_nentries = ch->local_nentries; + XPC_NOTIFY_IRQ_SEND_SN2(ch, XPC_IPI_OPENREQUEST, irq_flags); +} + +static void +xpc_IPI_send_openreply_sn2(struct xpc_channel *ch, unsigned long *irq_flags) +{ + struct xpc_openclose_args *args = ch->local_openclose_args; + + args->remote_nentries = ch->remote_nentries; + args->local_nentries = ch->local_nentries; + args->local_msgqueue_pa = __pa(ch->local_msgqueue); + XPC_NOTIFY_IRQ_SEND_SN2(ch, XPC_IPI_OPENREPLY, irq_flags); +} + +static void +xpc_IPI_send_msgrequest_sn2(struct xpc_channel *ch) +{ + XPC_NOTIFY_IRQ_SEND_SN2(ch, XPC_IPI_MSGREQUEST, NULL); +} + +static void +xpc_IPI_send_local_msgrequest_sn2(struct xpc_channel *ch) +{ + XPC_NOTIFY_IRQ_SEND_LOCAL_SN2(ch, XPC_IPI_MSGREQUEST); +} + +/* + * This next set of functions are used to keep track of when a partition is + * potentially engaged in accessing memory belonging to another partition. + */ + +static void +xpc_mark_partition_engaged_sn2(struct xpc_partition *part) +{ + unsigned long irq_flags; + AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + + (XPC_ENGAGED_PARTITIONS_AMO * + sizeof(AMO_t))); + + local_irq_save(irq_flags); + + /* set bit corresponding to our partid in remote partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, + (1UL << sn_partition_id)); + /* + * We must always use the nofault function regardless of whether we + * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we + * didn't, we'd never know that the other partition is down and would + * keep sending IPIs and AMOs to it until the heartbeat times out. + */ + (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), + xp_nofault_PIOR_target)); + + local_irq_restore(irq_flags); +} + +static void +xpc_mark_partition_disengaged_sn2(struct xpc_partition *part) +{ + unsigned long irq_flags; + AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + + (XPC_ENGAGED_PARTITIONS_AMO * + sizeof(AMO_t))); + + local_irq_save(irq_flags); + + /* clear bit corresponding to our partid in remote partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, + ~(1UL << sn_partition_id)); + /* + * We must always use the nofault function regardless of whether we + * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we + * didn't, we'd never know that the other partition is down and would + * keep sending IPIs and AMOs to it until the heartbeat times out. + */ + (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), + xp_nofault_PIOR_target)); + + local_irq_restore(irq_flags); +} + +static void +xpc_request_partition_disengage_sn2(struct xpc_partition *part) +{ + unsigned long irq_flags; + AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + + (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t))); + + local_irq_save(irq_flags); + + /* set bit corresponding to our partid in remote partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, + (1UL << sn_partition_id)); + /* + * We must always use the nofault function regardless of whether we + * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we + * didn't, we'd never know that the other partition is down and would + * keep sending IPIs and AMOs to it until the heartbeat times out. + */ + (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), + xp_nofault_PIOR_target)); + + local_irq_restore(irq_flags); +} + +static void +xpc_cancel_partition_disengage_request_sn2(struct xpc_partition *part) +{ + unsigned long irq_flags; + AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + + (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t))); + + local_irq_save(irq_flags); + + /* clear bit corresponding to our partid in remote partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, + ~(1UL << sn_partition_id)); + /* + * We must always use the nofault function regardless of whether we + * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we + * didn't, we'd never know that the other partition is down and would + * keep sending IPIs and AMOs to it until the heartbeat times out. + */ + (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), + xp_nofault_PIOR_target)); + + local_irq_restore(irq_flags); +} + +static u64 +xpc_partition_engaged_sn2(u64 partid_mask) +{ + AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; + + /* return our partition's AMO variable ANDed with partid_mask */ + return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & + partid_mask); +} + +static u64 +xpc_partition_disengage_requested_sn2(u64 partid_mask) +{ + AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO; + + /* return our partition's AMO variable ANDed with partid_mask */ + return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & + partid_mask); +} + +static void +xpc_clear_partition_engaged_sn2(u64 partid_mask) +{ + AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; + + /* clear bit(s) based on partid_mask in our partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, + ~partid_mask); +} + +static void +xpc_clear_partition_disengage_request_sn2(u64 partid_mask) +{ + AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO; + + /* clear bit(s) based on partid_mask in our partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, + ~partid_mask); +} + static enum xp_retval xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) { @@ -79,7 +440,7 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) } /* clear xpc_vars */ - memset(xpc_vars, 0, sizeof(struct xpc_vars)); + memset(xpc_vars, 0, sizeof(struct xpc_vars_sn2)); xpc_vars->version = XPC_V_VERSION; xpc_vars->act_nasid = cpuid_to_nasid(0); @@ -94,15 +455,446 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) /* initialize the activate IRQ related AMO variables */ for (i = 0; i < xp_nasid_mask_words; i++) - (void)xpc_IPI_init(XPC_ACTIVATE_IRQ_AMOS + i); + (void)xpc_IPI_init_sn2(XPC_ACTIVATE_IRQ_AMOS + i); /* initialize the engaged remote partitions related AMO variables */ - (void)xpc_IPI_init(XPC_ENGAGED_PARTITIONS_AMO); - (void)xpc_IPI_init(XPC_DISENGAGE_REQUEST_AMO); + (void)xpc_IPI_init_sn2(XPC_ENGAGED_PARTITIONS_AMO); + (void)xpc_IPI_init_sn2(XPC_DISENGAGE_REQUEST_AMO); + + return xpSuccess; +} + +static void +xpc_increment_heartbeat_sn2(void) +{ + xpc_vars->heartbeat++; +} + +static void +xpc_offline_heartbeat_sn2(void) +{ + xpc_increment_heartbeat_sn2(); + xpc_vars->heartbeat_offline = 1; +} + +static void +xpc_online_heartbeat_sn2(void) +{ + xpc_increment_heartbeat_sn2(); + xpc_vars->heartbeat_offline = 0; +} + +static void +xpc_heartbeat_init_sn2(void) +{ + DBUG_ON(xpc_vars == NULL); + + bitmap_zero(xpc_vars->heartbeating_to_mask, XP_MAX_NPARTITIONS_SN2); + xpc_heartbeating_to_mask = &xpc_vars->heartbeating_to_mask[0]; + xpc_online_heartbeat_sn2(); +} + +static void +xpc_heartbeat_exit_sn2(void) +{ + xpc_offline_heartbeat_sn2(); +} + +/* + * At periodic intervals, scan through all active partitions and ensure + * their heartbeat is still active. If not, the partition is deactivated. + */ +static void +xpc_check_remote_hb_sn2(void) +{ + struct xpc_vars_sn2 *remote_vars; + struct xpc_partition *part; + short partid; + enum xp_retval ret; + + remote_vars = (struct xpc_vars_sn2 *)xpc_remote_copy_buffer; + + for (partid = 0; partid < xp_max_npartitions; partid++) { + + if (xpc_exiting) + break; + + if (partid == sn_partition_id) + continue; + + part = &xpc_partitions[partid]; + + if (part->act_state == XPC_P_INACTIVE || + part->act_state == XPC_P_DEACTIVATING) { + continue; + } + + /* pull the remote_hb cache line */ + ret = xp_remote_memcpy(remote_vars, + (void *)part->remote_vars_pa, + XPC_RP_VARS_SIZE); + if (ret != xpSuccess) { + XPC_DEACTIVATE_PARTITION(part, ret); + continue; + } + + dev_dbg(xpc_part, "partid = %d, heartbeat = %ld, last_heartbeat" + " = %ld, heartbeat_offline = %ld, HB_mask[0] = 0x%lx\n", + partid, remote_vars->heartbeat, part->last_heartbeat, + remote_vars->heartbeat_offline, + remote_vars->heartbeating_to_mask[0]); + + if (((remote_vars->heartbeat == part->last_heartbeat) && + (remote_vars->heartbeat_offline == 0)) || + !xpc_hb_allowed(sn_partition_id, + &remote_vars->heartbeating_to_mask)) { + + XPC_DEACTIVATE_PARTITION(part, xpNoHeartbeat); + continue; + } + + part->last_heartbeat = remote_vars->heartbeat; + } +} + +/* + * Get a copy of the remote partition's XPC variables from the reserved page. + * + * remote_vars points to a buffer that is cacheline aligned for BTE copies and + * assumed to be of size XPC_RP_VARS_SIZE. + */ +static enum xp_retval +xpc_get_remote_vars_sn2(u64 remote_vars_pa, struct xpc_vars_sn2 *remote_vars) +{ + enum xp_retval ret; + + if (remote_vars_pa == 0) + return xpVarsNotSet; + + /* pull over the cross partition variables */ + ret = xp_remote_memcpy(remote_vars, (void *)remote_vars_pa, + XPC_RP_VARS_SIZE); + if (ret != xpSuccess) + return ret; + + if (XPC_VERSION_MAJOR(remote_vars->version) != + XPC_VERSION_MAJOR(XPC_V_VERSION)) { + return xpBadVersion; + } return xpSuccess; } +static void +xpc_initiate_partition_activation_sn2(struct xpc_rsvd_page *remote_rp, + u64 remote_rp_pa, int nasid) +{ + xpc_IPI_send_local_activate(nasid); +} + +/* + * Update the remote partition's info. + */ +static void +xpc_update_partition_info_sn2(struct xpc_partition *part, u8 remote_rp_version, + struct timespec *remote_rp_stamp, + u64 remote_rp_pa, u64 remote_vars_pa, + struct xpc_vars_sn2 *remote_vars) +{ + part->remote_rp_version = remote_rp_version; + dev_dbg(xpc_part, " remote_rp_version = 0x%016x\n", + part->remote_rp_version); + + part->remote_rp_stamp = *remote_rp_stamp; + dev_dbg(xpc_part, " remote_rp_stamp (tv_sec = 0x%lx tv_nsec = 0x%lx\n", + part->remote_rp_stamp.tv_sec, part->remote_rp_stamp.tv_nsec); + + part->remote_rp_pa = remote_rp_pa; + dev_dbg(xpc_part, " remote_rp_pa = 0x%016lx\n", part->remote_rp_pa); + + part->remote_vars_pa = remote_vars_pa; + dev_dbg(xpc_part, " remote_vars_pa = 0x%016lx\n", + part->remote_vars_pa); + + part->last_heartbeat = remote_vars->heartbeat; + dev_dbg(xpc_part, " last_heartbeat = 0x%016lx\n", + part->last_heartbeat); + + part->remote_vars_part_pa = remote_vars->vars_part_pa; + dev_dbg(xpc_part, " remote_vars_part_pa = 0x%016lx\n", + part->remote_vars_part_pa); + + part->remote_act_nasid = remote_vars->act_nasid; + dev_dbg(xpc_part, " remote_act_nasid = 0x%x\n", + part->remote_act_nasid); + + part->remote_act_phys_cpuid = remote_vars->act_phys_cpuid; + dev_dbg(xpc_part, " remote_act_phys_cpuid = 0x%x\n", + part->remote_act_phys_cpuid); + + part->remote_amos_page_pa = remote_vars->amos_page_pa; + dev_dbg(xpc_part, " remote_amos_page_pa = 0x%lx\n", + part->remote_amos_page_pa); + + part->remote_vars_version = remote_vars->version; + dev_dbg(xpc_part, " remote_vars_version = 0x%x\n", + part->remote_vars_version); +} + +/* + * Prior code has determined the nasid which generated an IPI. Inspect + * that nasid to determine if its partition needs to be activated or + * deactivated. + * + * A partition is consider "awaiting activation" if our partition + * flags indicate it is not active and it has a heartbeat. A + * partition is considered "awaiting deactivation" if our partition + * flags indicate it is active but it has no heartbeat or it is not + * sending its heartbeat to us. + * + * To determine the heartbeat, the remote nasid must have a properly + * initialized reserved page. + */ +static void +xpc_identify_act_IRQ_req_sn2(int nasid) +{ + struct xpc_rsvd_page *remote_rp; + struct xpc_vars_sn2 *remote_vars; + u64 remote_rp_pa; + u64 remote_vars_pa; + int remote_rp_version; + int reactivate = 0; + int stamp_diff; + struct timespec remote_rp_stamp = { 0, 0 }; /*>>> ZERO_STAMP */ + short partid; + struct xpc_partition *part; + enum xp_retval ret; + + /* pull over the reserved page structure */ + + remote_rp = (struct xpc_rsvd_page *)xpc_remote_copy_buffer; + + ret = xpc_get_remote_rp(nasid, NULL, remote_rp, &remote_rp_pa); + if (ret != xpSuccess) { + dev_warn(xpc_part, "unable to get reserved page from nasid %d, " + "which sent interrupt, reason=%d\n", nasid, ret); + return; + } + + remote_vars_pa = remote_rp->sn.vars_pa; + remote_rp_version = remote_rp->version; + if (XPC_SUPPORTS_RP_STAMP(remote_rp_version)) + remote_rp_stamp = remote_rp->stamp; + + partid = remote_rp->SAL_partid; + part = &xpc_partitions[partid]; + + /* pull over the cross partition variables */ + + remote_vars = (struct xpc_vars_sn2 *)xpc_remote_copy_buffer; + + ret = xpc_get_remote_vars_sn2(remote_vars_pa, remote_vars); + if (ret != xpSuccess) { + + dev_warn(xpc_part, "unable to get XPC variables from nasid %d, " + "which sent interrupt, reason=%d\n", nasid, ret); + + XPC_DEACTIVATE_PARTITION(part, ret); + return; + } + + part->act_IRQ_rcvd++; + + dev_dbg(xpc_part, "partid for nasid %d is %d; IRQs = %d; HB = " + "%ld:0x%lx\n", (int)nasid, (int)partid, part->act_IRQ_rcvd, + remote_vars->heartbeat, remote_vars->heartbeating_to_mask[0]); + + if (xpc_partition_disengaged(part) && + part->act_state == XPC_P_INACTIVE) { + + xpc_update_partition_info_sn2(part, remote_rp_version, + &remote_rp_stamp, remote_rp_pa, + remote_vars_pa, remote_vars); + + if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) { + if (xpc_partition_disengage_requested(1UL << partid)) { + /* + * Other side is waiting on us to disengage, + * even though we already have. + */ + return; + } + + } else { + /* other side doesn't support disengage requests */ + xpc_clear_partition_disengage_request(1UL << partid); + } + + xpc_activate_partition(part); + return; + } + + DBUG_ON(part->remote_rp_version == 0); + DBUG_ON(part->remote_vars_version == 0); + + if (!XPC_SUPPORTS_RP_STAMP(part->remote_rp_version)) { + DBUG_ON(XPC_SUPPORTS_DISENGAGE_REQUEST(part-> + remote_vars_version)); + + if (!XPC_SUPPORTS_RP_STAMP(remote_rp_version)) { + DBUG_ON(XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars-> + version)); + /* see if the other side rebooted */ + if (part->remote_amos_page_pa == + remote_vars->amos_page_pa && + xpc_hb_allowed(sn_partition_id, + &remote_vars->heartbeating_to_mask)) { + /* doesn't look that way, so ignore the IPI */ + return; + } + } + + /* + * Other side rebooted and previous XPC didn't support the + * disengage request, so we don't need to do anything special. + */ + + xpc_update_partition_info_sn2(part, remote_rp_version, + &remote_rp_stamp, remote_rp_pa, + remote_vars_pa, remote_vars); + part->reactivate_nasid = nasid; + XPC_DEACTIVATE_PARTITION(part, xpReactivating); + return; + } + + DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)); + + if (!XPC_SUPPORTS_RP_STAMP(remote_rp_version)) { + DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->version)); + + /* + * Other side rebooted and previous XPC did support the + * disengage request, but the new one doesn't. + */ + + xpc_clear_partition_engaged(1UL << partid); + xpc_clear_partition_disengage_request(1UL << partid); + + xpc_update_partition_info_sn2(part, remote_rp_version, + &remote_rp_stamp, remote_rp_pa, + remote_vars_pa, remote_vars); + reactivate = 1; + + } else { + DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->version)); + + stamp_diff = xpc_compare_stamps(&part->remote_rp_stamp, + &remote_rp_stamp); + if (stamp_diff != 0) { + DBUG_ON(stamp_diff >= 0); + + /* + * Other side rebooted and the previous XPC did support + * the disengage request, as does the new one. + */ + + DBUG_ON(xpc_partition_engaged(1UL << partid)); + DBUG_ON(xpc_partition_disengage_requested(1UL << + partid)); + + xpc_update_partition_info_sn2(part, remote_rp_version, + &remote_rp_stamp, + remote_rp_pa, + remote_vars_pa, + remote_vars); + reactivate = 1; + } + } + + if (part->disengage_request_timeout > 0 && + !xpc_partition_disengaged(part)) { + /* still waiting on other side to disengage from us */ + return; + } + + if (reactivate) { + part->reactivate_nasid = nasid; + XPC_DEACTIVATE_PARTITION(part, xpReactivating); + + } else if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version) && + xpc_partition_disengage_requested(1UL << partid)) { + XPC_DEACTIVATE_PARTITION(part, xpOtherGoingDown); + } +} + +/* + * Loop through the activation AMO variables and process any bits + * which are set. Each bit indicates a nasid sending a partition + * activation or deactivation request. + * + * Return #of IRQs detected. + */ +int +xpc_identify_act_IRQ_sender_sn2(void) +{ + int word, bit; + u64 nasid_mask; + u64 nasid; /* remote nasid */ + int n_IRQs_detected = 0; + AMO_t *act_amos; + + act_amos = xpc_vars->amos_page + XPC_ACTIVATE_IRQ_AMOS; + + /* scan through act AMO variable looking for non-zero entries */ + for (word = 0; word < xp_nasid_mask_words; word++) { + + if (xpc_exiting) + break; + + nasid_mask = xpc_IPI_receive_sn2(&act_amos[word]); + if (nasid_mask == 0) { + /* no IRQs from nasids in this variable */ + continue; + } + + dev_dbg(xpc_part, "AMO[%d] gave back 0x%lx\n", word, + nasid_mask); + + /* + * If this nasid has been added to the machine since + * our partition was reset, this will retain the + * remote nasid in our reserved pages machine mask. + * This is used in the event of module reload. + */ + xpc_mach_nasids[word] |= nasid_mask; + + /* locate the nasid(s) which sent interrupts */ + + for (bit = 0; bit < (8 * sizeof(u64)); bit++) { + if (nasid_mask & (1UL << bit)) { + n_IRQs_detected++; + nasid = XPC_NASID_FROM_W_B(word, bit); + dev_dbg(xpc_part, "interrupt from nasid %ld\n", + nasid); + xpc_identify_act_IRQ_req_sn2(nasid); + } + } + } + return n_IRQs_detected; +} + +static void +xpc_process_act_IRQ_rcvd_sn2(int n_IRQs_expected) +{ + int n_IRQs_detected; + + n_IRQs_detected = xpc_identify_act_IRQ_sender_sn2(); + if (n_IRQs_detected < n_IRQs_expected) { + /* retry once to help avoid missing AMO */ + (void)xpc_identify_act_IRQ_sender_sn2(); + } +} + /* * Setup the infrastructure necessary to support XPartition Communication * between the specified remote partition and the local one. @@ -177,7 +969,7 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) part->remote_openclose_args_pa = 0; - part->local_IPI_amo_va = xpc_IPI_init(partid); + part->local_IPI_amo_va = xpc_IPI_init_sn2(partid); part->local_IPI_amo = 0; spin_lock_init(&part->IPI_lock); @@ -468,6 +1260,28 @@ xpc_make_first_contact_sn2(struct xpc_partition *part) { enum xp_retval ret; + /* + * Register the remote partition's AMOs with SAL so it can handle + * and cleanup errors within that address range should the remote + * partition go down. We don't unregister this range because it is + * difficult to tell when outstanding writes to the remote partition + * are finished and thus when it is safe to unregister. This should + * not result in wasted space in the SAL xp_addr_region table because + * we should get the same page for remote_amos_page_pa after module + * reloads and system reboots. + */ + if (sn_register_xp_addr_region(part->remote_amos_page_pa, + PAGE_SIZE, 1) < 0) { + dev_warn(xpc_part, "xpc_activating(%d) failed to register " + "xp_addr region\n", XPC_PARTID(part)); + + ret = xpPhysAddrRegFailed; + XPC_DEACTIVATE_PARTITION(part, ret); + return ret; + } + + xpc_IPI_send_activated(part); + while ((ret = xpc_pull_remote_vars_part_sn2(part)) != xpSuccess) { if (ret != xpRetry) { XPC_DEACTIVATE_PARTITION(part, ret); @@ -651,15 +1465,370 @@ xpc_get_deliverable_msg_sn2(struct xpc_channel *ch) return msg; } +/* + * Now we actually send the messages that are ready to be sent by advancing + * the local message queue's Put value and then send an IPI to the recipient + * partition. + */ +static void +xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put) +{ + struct xpc_msg *msg; + s64 put = initial_put + 1; + int send_IPI = 0; + + while (1) { + + while (1) { + if (put == ch->w_local_GP.put) + break; + + msg = (struct xpc_msg *)((u64)ch->local_msgqueue + + (put % ch->local_nentries) * + ch->msg_size); + + if (!(msg->flags & XPC_M_READY)) + break; + + put++; + } + + if (put == initial_put) { + /* nothing's changed */ + break; + } + + if (cmpxchg_rel(&ch->local_GP->put, initial_put, put) != + initial_put) { + /* someone else beat us to it */ + DBUG_ON(ch->local_GP->put < initial_put); + break; + } + + /* we just set the new value of local_GP->put */ + + dev_dbg(xpc_chan, "local_GP->put changed to %ld, partid=%d, " + "channel=%d\n", put, ch->partid, ch->number); + + send_IPI = 1; + + /* + * We need to ensure that the message referenced by + * local_GP->put is not XPC_M_READY or that local_GP->put + * equals w_local_GP.put, so we'll go have a look. + */ + initial_put = put; + } + + if (send_IPI) + xpc_IPI_send_msgrequest_sn2(ch); +} + +/* + * Allocate an entry for a message from the message queue associated with the + * specified channel. + */ +static enum xp_retval +xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags, + struct xpc_msg **address_of_msg) +{ + struct xpc_msg *msg; + enum xp_retval ret; + s64 put; + + /* this reference will be dropped in xpc_send_msg_sn2() */ + xpc_msgqueue_ref(ch); + + if (ch->flags & XPC_C_DISCONNECTING) { + xpc_msgqueue_deref(ch); + return ch->reason; + } + if (!(ch->flags & XPC_C_CONNECTED)) { + xpc_msgqueue_deref(ch); + return xpNotConnected; + } + + /* + * Get the next available message entry from the local message queue. + * If none are available, we'll make sure that we grab the latest + * GP values. + */ + ret = xpTimeout; + + while (1) { + + put = ch->w_local_GP.put; + rmb(); /* guarantee that .put loads before .get */ + if (put - ch->w_remote_GP.get < ch->local_nentries) { + + /* There are available message entries. We need to try + * to secure one for ourselves. We'll do this by trying + * to increment w_local_GP.put as long as someone else + * doesn't beat us to it. If they do, we'll have to + * try again. + */ + if (cmpxchg(&ch->w_local_GP.put, put, put + 1) == put) { + /* we got the entry referenced by put */ + break; + } + continue; /* try again */ + } + + /* + * There aren't any available msg entries at this time. + * + * In waiting for a message entry to become available, + * we set a timeout in case the other side is not + * sending completion IPIs. This lets us fake an IPI + * that will cause the IPI handler to fetch the latest + * GP values as if an IPI was sent by the other side. + */ + if (ret == xpTimeout) + xpc_IPI_send_local_msgrequest_sn2(ch); + + if (flags & XPC_NOWAIT) { + xpc_msgqueue_deref(ch); + return xpNoWait; + } + + ret = xpc_allocate_msg_wait(ch); + if (ret != xpInterrupted && ret != xpTimeout) { + xpc_msgqueue_deref(ch); + return ret; + } + } + + /* get the message's address and initialize it */ + msg = (struct xpc_msg *)((u64)ch->local_msgqueue + + (put % ch->local_nentries) * ch->msg_size); + + DBUG_ON(msg->flags != 0); + msg->number = put; + + dev_dbg(xpc_chan, "w_local_GP.put changed to %ld; msg=0x%p, " + "msg_number=%ld, partid=%d, channel=%d\n", put + 1, + (void *)msg, msg->number, ch->partid, ch->number); + + *address_of_msg = msg; + + return xpSuccess; +} + +/* + * Common code that does the actual sending of the message by advancing the + * local message queue's Put value and sends an IPI to the partition the + * message is being sent to. + */ +static enum xp_retval +xpc_send_msg_sn2(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type, + xpc_notify_func func, void *key) +{ + enum xp_retval ret = xpSuccess; + struct xpc_notify *notify = notify; + s64 put, msg_number = msg->number; + + DBUG_ON(notify_type == XPC_N_CALL && func == NULL); + DBUG_ON((((u64)msg - (u64)ch->local_msgqueue) / ch->msg_size) != + msg_number % ch->local_nentries); + DBUG_ON(msg->flags & XPC_M_READY); + + if (ch->flags & XPC_C_DISCONNECTING) { + /* drop the reference grabbed in xpc_allocate_msg_sn2() */ + xpc_msgqueue_deref(ch); + return ch->reason; + } + + if (notify_type != 0) { + /* + * Tell the remote side to send an ACK interrupt when the + * message has been delivered. + */ + msg->flags |= XPC_M_INTERRUPT; + + atomic_inc(&ch->n_to_notify); + + notify = &ch->notify_queue[msg_number % ch->local_nentries]; + notify->func = func; + notify->key = key; + notify->type = notify_type; + + /* >>> is a mb() needed here? */ + + if (ch->flags & XPC_C_DISCONNECTING) { + /* + * An error occurred between our last error check and + * this one. We will try to clear the type field from + * the notify entry. If we succeed then + * xpc_disconnect_channel() didn't already process + * the notify entry. + */ + if (cmpxchg(¬ify->type, notify_type, 0) == + notify_type) { + atomic_dec(&ch->n_to_notify); + ret = ch->reason; + } + + /* drop reference grabbed in xpc_allocate_msg_sn2() */ + xpc_msgqueue_deref(ch); + return ret; + } + } + + msg->flags |= XPC_M_READY; + + /* + * The preceding store of msg->flags must occur before the following + * load of ch->local_GP->put. + */ + mb(); + + /* see if the message is next in line to be sent, if so send it */ + + put = ch->local_GP->put; + if (put == msg_number) + xpc_send_msgs_sn2(ch, put); + + /* drop the reference grabbed in xpc_allocate_msg_sn2() */ + xpc_msgqueue_deref(ch); + return ret; +} + +/* + * Now we actually acknowledge the messages that have been delivered and ack'd + * by advancing the cached remote message queue's Get value and if requested + * send an IPI to the message sender's partition. + */ +static void +xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) +{ + struct xpc_msg *msg; + s64 get = initial_get + 1; + int send_IPI = 0; + + while (1) { + + while (1) { + if (get == ch->w_local_GP.get) + break; + + msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + + (get % ch->remote_nentries) * + ch->msg_size); + + if (!(msg->flags & XPC_M_DONE)) + break; + + msg_flags |= msg->flags; + get++; + } + + if (get == initial_get) { + /* nothing's changed */ + break; + } + + if (cmpxchg_rel(&ch->local_GP->get, initial_get, get) != + initial_get) { + /* someone else beat us to it */ + DBUG_ON(ch->local_GP->get <= initial_get); + break; + } + + /* we just set the new value of local_GP->get */ + + dev_dbg(xpc_chan, "local_GP->get changed to %ld, partid=%d, " + "channel=%d\n", get, ch->partid, ch->number); + + send_IPI = (msg_flags & XPC_M_INTERRUPT); + + /* + * We need to ensure that the message referenced by + * local_GP->get is not XPC_M_DONE or that local_GP->get + * equals w_local_GP.get, so we'll go have a look. + */ + initial_get = get; + } + + if (send_IPI) + xpc_IPI_send_msgrequest_sn2(ch); +} + +static void +xpc_received_msg_sn2(struct xpc_channel *ch, struct xpc_msg *msg) +{ + s64 get; + s64 msg_number = msg->number; + + dev_dbg(xpc_chan, "msg=0x%p, msg_number=%ld, partid=%d, channel=%d\n", + (void *)msg, msg_number, ch->partid, ch->number); + + DBUG_ON((((u64)msg - (u64)ch->remote_msgqueue) / ch->msg_size) != + msg_number % ch->remote_nentries); + DBUG_ON(msg->flags & XPC_M_DONE); + + msg->flags |= XPC_M_DONE; + + /* + * The preceding store of msg->flags must occur before the following + * load of ch->local_GP->get. + */ + mb(); + + /* + * See if this message is next in line to be acknowledged as having + * been delivered. + */ + get = ch->local_GP->get; + if (get == msg_number) + xpc_acknowledge_msgs_sn2(ch, get, msg->flags); +} + void xpc_init_sn2(void) { xpc_rsvd_page_init = xpc_rsvd_page_init_sn2; + xpc_increment_heartbeat = xpc_increment_heartbeat_sn2; + xpc_offline_heartbeat = xpc_offline_heartbeat_sn2; + xpc_online_heartbeat = xpc_online_heartbeat_sn2; + xpc_heartbeat_init = xpc_heartbeat_init_sn2; + xpc_heartbeat_exit = xpc_heartbeat_exit_sn2; + xpc_check_remote_hb = xpc_check_remote_hb_sn2; + + xpc_initiate_partition_activation = + xpc_initiate_partition_activation_sn2; + xpc_process_act_IRQ_rcvd = xpc_process_act_IRQ_rcvd_sn2; xpc_setup_infrastructure = xpc_setup_infrastructure_sn2; xpc_teardown_infrastructure = xpc_teardown_infrastructure_sn2; xpc_make_first_contact = xpc_make_first_contact_sn2; xpc_get_IPI_flags = xpc_get_IPI_flags_sn2; xpc_get_deliverable_msg = xpc_get_deliverable_msg_sn2; + + xpc_mark_partition_engaged = xpc_mark_partition_engaged_sn2; + xpc_mark_partition_disengaged = xpc_mark_partition_disengaged_sn2; + xpc_request_partition_disengage = xpc_request_partition_disengage_sn2; + xpc_cancel_partition_disengage_request = + xpc_cancel_partition_disengage_request_sn2; + xpc_partition_engaged = xpc_partition_engaged_sn2; + xpc_partition_disengage_requested = + xpc_partition_disengage_requested_sn2; + xpc_clear_partition_engaged = xpc_clear_partition_engaged_sn2; + xpc_clear_partition_disengage_request = + xpc_clear_partition_disengage_request_sn2; + + xpc_IPI_send_local_activate = xpc_IPI_send_local_activate_sn2; + xpc_IPI_send_activated = xpc_IPI_send_activated_sn2; + xpc_IPI_send_local_reactivate = xpc_IPI_send_local_reactivate_sn2; + xpc_IPI_send_disengage = xpc_IPI_send_disengage_sn2; + + xpc_IPI_send_closerequest = xpc_IPI_send_closerequest_sn2; + xpc_IPI_send_closereply = xpc_IPI_send_closereply_sn2; + xpc_IPI_send_openrequest = xpc_IPI_send_openrequest_sn2; + xpc_IPI_send_openreply = xpc_IPI_send_openreply_sn2; + + xpc_allocate_msg = xpc_allocate_msg_sn2; + + xpc_send_msg = xpc_send_msg_sn2; + xpc_received_msg = xpc_received_msg_sn2; } void diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index 770f0a8c669..32c577b8d0d 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c @@ -19,15 +19,22 @@ /* >>> uv_gpa() is defined in */ #define uv_gpa(_a) ((unsigned long)_a) -/* >>> temporarily define next three items for xpc.h */ -#define SGI_XPC_ACTIVATE 23 -#define SGI_XPC_NOTIFY 24 -#define sn_send_IPI_phys(_a, _b, _c, _d) - #include "xpc.h" +static DECLARE_BITMAP(xpc_heartbeating_to_mask_uv, XP_MAX_NPARTITIONS_UV); + static void *xpc_activate_mq; +static void +xpc_IPI_send_local_activate_uv(struct xpc_partition *part) +{ + /* + * >>> make our side think that the remote parition sent an activate + * >>> message our way. Also do what the activate IRQ handler would + * >>> do had one really been sent. + */ +} + static enum xp_retval xpc_rsvd_page_init_uv(struct xpc_rsvd_page *rp) { @@ -36,6 +43,41 @@ xpc_rsvd_page_init_uv(struct xpc_rsvd_page *rp) return xpSuccess; } +static void +xpc_increment_heartbeat_uv(void) +{ + /* >>> send heartbeat msg to xpc_heartbeating_to_mask partids */ +} + +static void +xpc_heartbeat_init_uv(void) +{ + bitmap_zero(xpc_heartbeating_to_mask_uv, XP_MAX_NPARTITIONS_UV); + xpc_heartbeating_to_mask = &xpc_heartbeating_to_mask_uv[0]; +} + +static void +xpc_heartbeat_exit_uv(void) +{ + /* >>> send heartbeat_offline msg to xpc_heartbeating_to_mask partids */ +} + +static void +xpc_initiate_partition_activation_uv(struct xpc_rsvd_page *remote_rp, + u64 remote_rp_pa, int nasid) +{ + short partid = remote_rp->SAL_partid; + struct xpc_partition *part = &xpc_partitions[partid]; + +/* + * >>> setup part structure with the bits of info we can glean from the rp + * >>> part->remote_rp_pa = remote_rp_pa; + * >>> part->sn.uv.activate_mq_gpa = remote_rp->sn.activate_mq_gpa; + */ + + xpc_IPI_send_local_activate_uv(part); +} + /* * Setup the infrastructure necessary to support XPartition Communication * between the specified remote partition and the local one. @@ -83,6 +125,11 @@ void xpc_init_uv(void) { xpc_rsvd_page_init = xpc_rsvd_page_init_uv; + xpc_increment_heartbeat = xpc_increment_heartbeat_uv; + xpc_heartbeat_init = xpc_heartbeat_init_uv; + xpc_heartbeat_exit = xpc_heartbeat_exit_uv; + xpc_initiate_partition_activation = + xpc_initiate_partition_activation_uv; xpc_setup_infrastructure = xpc_setup_infrastructure_uv; xpc_teardown_infrastructure = xpc_teardown_infrastructure_uv; xpc_make_first_contact = xpc_make_first_contact_uv; -- cgit v1.2.3 From aaa3cd694c0c4ae534e8aafdf4227e395c57d6bd Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:07 -0700 Subject: sgi-xp: base xpc_rsvd_page's timestamp on jiffies Change XPC's reserved page timestamp to be based on jiffies. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xpc.h | 26 +++----------------------- drivers/misc/sgi-xp/xpc_main.c | 16 ++++++++-------- drivers/misc/sgi-xp/xpc_partition.c | 33 +++++++++++++++++---------------- drivers/misc/sgi-xp/xpc_sn2.c | 16 ++++++---------- 4 files changed, 34 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index a3a67485cf8..56bf5dcc391 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -115,8 +115,8 @@ struct xpc_rsvd_page { u64 vars_pa; /* physical address of struct xpc_vars */ u64 activate_mq_gpa; /* global phys address of activate_mq */ } sn; - struct timespec stamp; /* time when reserved page was setup by XPC */ - u64 pad2[9]; /* align to last u64 in 2nd 64-byte cacheline */ + unsigned long stamp; /* time when reserved page was setup by XPC */ + u64 pad2[10]; /* align to last u64 in 2nd 64-byte cacheline */ u64 SAL_nasids_size; /* SAL: size of each nasid mask in bytes */ }; @@ -125,26 +125,6 @@ struct xpc_rsvd_page { #define XPC_SUPPORTS_RP_STAMP(_version) \ (_version >= _XPC_VERSION(1, 1)) -#define ZERO_STAMP ((struct timespec){0, 0}) -/* - * compare stamps - the return value is: - * - * < 0, if stamp1 < stamp2 - * = 0, if stamp1 == stamp2 - * > 0, if stamp1 > stamp2 - */ -static inline int -xpc_compare_stamps(struct timespec *stamp1, struct timespec *stamp2) -{ - int ret; - - ret = stamp1->tv_sec - stamp2->tv_sec; - if (ret == 0) - ret = stamp1->tv_nsec - stamp2->tv_nsec; - - return ret; -} - /* * Define the structures by which XPC variables can be exported to other * partitions. (There are two: struct xpc_vars and struct xpc_vars_part) @@ -492,7 +472,7 @@ struct xpc_partition { /* XPC HB infrastructure */ u8 remote_rp_version; /* version# of partition's rsvd pg */ - struct timespec remote_rp_stamp; /* time when rsvd pg was initialized */ + unsigned long remote_rp_stamp; /* time when rsvd pg was initialized */ u64 remote_rp_pa; /* phys addr of partition's rsvd pg */ u64 remote_vars_pa; /* phys addr of partition's vars */ u64 remote_vars_part_pa; /* phys addr of partition's vars part */ diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index 10dac3652b2..4a6eb377475 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -233,7 +233,7 @@ xpc_timeout_partition_disengage_request(unsigned long data) { struct xpc_partition *part = (struct xpc_partition *)data; - DBUG_ON(time_before(jiffies, part->disengage_request_timeout)); + DBUG_ON(time_is_after_jiffies(part->disengage_request_timeout)); (void)xpc_partition_disengaged(part); @@ -262,7 +262,7 @@ xpc_hb_beater(unsigned long dummy) { xpc_increment_heartbeat(); - if (time_after_eq(jiffies, xpc_hb_check_timeout)) + if (time_is_before_eq_jiffies(xpc_hb_check_timeout)) wake_up_interruptible(&xpc_act_IRQ_wq); xpc_hb_timer.expires = jiffies + (xpc_hb_interval * HZ); @@ -312,7 +312,7 @@ xpc_hb_checker(void *ignore) atomic_read(&xpc_act_IRQ_rcvd) - last_IRQ_count); /* checking of remote heartbeats is skewed by IRQ handling */ - if (time_after_eq(jiffies, xpc_hb_check_timeout)) { + if (time_is_before_eq_jiffies(xpc_hb_check_timeout)) { dev_dbg(xpc_part, "checking remote heartbeats\n"); xpc_check_remote_hb(); @@ -344,8 +344,8 @@ xpc_hb_checker(void *ignore) (void)wait_event_interruptible(xpc_act_IRQ_wq, (last_IRQ_count < atomic_read(&xpc_act_IRQ_rcvd) - || time_after_eq(jiffies, - xpc_hb_check_timeout) || + || time_is_before_eq_jiffies( + xpc_hb_check_timeout) || xpc_exiting)); } @@ -929,7 +929,7 @@ xpc_do_exit(enum xp_retval reason) } if (xpc_partition_engaged(-1UL)) { - if (time_after(jiffies, printmsg_time)) { + if (time_is_before_jiffies(printmsg_time)) { dev_info(xpc_part, "waiting for remote " "partitions to disengage, timeout in " "%ld seconds\n", @@ -964,7 +964,7 @@ xpc_do_exit(enum xp_retval reason) DBUG_ON(xpc_any_hbs_allowed() != 0); /* indicate to others that our reserved page is uninitialized */ - xpc_rsvd_page->stamp = ZERO_STAMP; + xpc_rsvd_page->stamp = 0; if (reason == xpUnloading) { (void)unregister_die_notifier(&xpc_die_notifier); @@ -1295,7 +1295,7 @@ xpc_init(void) /* initialization was not successful */ out_4: /* indicate to others that our reserved page is uninitialized */ - xpc_rsvd_page->stamp = ZERO_STAMP; + xpc_rsvd_page->stamp = 0; (void)unregister_die_notifier(&xpc_die_notifier); (void)unregister_reboot_notifier(&xpc_reboot_notifier); diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 4e14effdedd..90ec5ca8c9a 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -152,6 +152,7 @@ xpc_setup_rsvd_page(void) { struct xpc_rsvd_page *rp; u64 rp_pa; + unsigned long new_stamp; /* get the local reserved page's address */ @@ -201,7 +202,10 @@ xpc_setup_rsvd_page(void) * This signifies to the remote partition that our reserved * page is initialized. */ - rp->stamp = CURRENT_TIME; + new_stamp = jiffies; + if (new_stamp == 0 || new_stamp == rp->stamp) + new_stamp++; + rp->stamp = new_stamp; return rp; } @@ -350,18 +354,8 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, discovered_nasids[i] |= remote_part_nasids[i]; } - /* check that the partid is valid and is for another partition */ - - if (remote_rp->SAL_partid < 0 || - remote_rp->SAL_partid >= xp_max_npartitions) { - return xpInvalidPartid; - } - - if (remote_rp->SAL_partid == sn_partition_id) - return xpLocalPartid; - - /* see if the rest of the reserved page has been set up by XPC */ - if (timespec_equal(&remote_rp->stamp, &ZERO_STAMP)) + /* see if the reserved page has been set up by XPC */ + if (remote_rp->stamp == 0) return xpRsvdPageNotSet; if (XPC_VERSION_MAJOR(remote_rp->version) != @@ -369,8 +363,15 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, return xpBadVersion; } - if (remote_rp->max_npartitions <= sn_partition_id) + /* check that both local and remote partids are valid for each side */ + if (remote_rp->SAL_partid < 0 || + remote_rp->SAL_partid >= xp_max_npartitions || + remote_rp->max_npartitions <= sn_partition_id) { return xpInvalidPartid; + } + + if (remote_rp->SAL_partid == sn_partition_id) + return xpLocalPartid; return xpSuccess; } @@ -388,8 +389,8 @@ xpc_partition_disengaged(struct xpc_partition *part) disengaged = (xpc_partition_engaged(1UL << partid) == 0); if (part->disengage_request_timeout) { if (!disengaged) { - if (time_before(jiffies, - part->disengage_request_timeout)) { + if (time_is_after_jiffies(part-> + disengage_request_timeout)) { /* timelimit hasn't been reached yet */ return 0; } diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index 89c0bb9a27f..7216df36bc7 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -597,8 +597,8 @@ xpc_initiate_partition_activation_sn2(struct xpc_rsvd_page *remote_rp, */ static void xpc_update_partition_info_sn2(struct xpc_partition *part, u8 remote_rp_version, - struct timespec *remote_rp_stamp, - u64 remote_rp_pa, u64 remote_vars_pa, + unsigned long *remote_rp_stamp, u64 remote_rp_pa, + u64 remote_vars_pa, struct xpc_vars_sn2 *remote_vars) { part->remote_rp_version = remote_rp_version; @@ -606,8 +606,8 @@ xpc_update_partition_info_sn2(struct xpc_partition *part, u8 remote_rp_version, part->remote_rp_version); part->remote_rp_stamp = *remote_rp_stamp; - dev_dbg(xpc_part, " remote_rp_stamp (tv_sec = 0x%lx tv_nsec = 0x%lx\n", - part->remote_rp_stamp.tv_sec, part->remote_rp_stamp.tv_nsec); + dev_dbg(xpc_part, " remote_rp_stamp = 0x%016lx\n", + part->remote_rp_stamp); part->remote_rp_pa = remote_rp_pa; dev_dbg(xpc_part, " remote_rp_pa = 0x%016lx\n", part->remote_rp_pa); @@ -664,8 +664,7 @@ xpc_identify_act_IRQ_req_sn2(int nasid) u64 remote_vars_pa; int remote_rp_version; int reactivate = 0; - int stamp_diff; - struct timespec remote_rp_stamp = { 0, 0 }; /*>>> ZERO_STAMP */ + unsigned long remote_rp_stamp = 0; short partid; struct xpc_partition *part; enum xp_retval ret; @@ -788,10 +787,7 @@ xpc_identify_act_IRQ_req_sn2(int nasid) } else { DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->version)); - stamp_diff = xpc_compare_stamps(&part->remote_rp_stamp, - &remote_rp_stamp); - if (stamp_diff != 0) { - DBUG_ON(stamp_diff >= 0); + if (remote_rp_stamp != part->remote_rp_stamp) { /* * Other side rebooted and the previous XPC did support -- cgit v1.2.3 From 97bf1aa1e1bb18de9bb1987c6eb9ad751bf08aab Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:08 -0700 Subject: sgi-xp: move xpc_allocate() into xpc_send()/xpc_send_notify() Move xpc_allocate() functionality into xpc_send()/xpc_send_notify() so xpc_allocate() no longer needs to be called by XPNET. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xp.h | 44 ++++++--------- drivers/misc/sgi-xp/xp_main.c | 23 +++----- drivers/misc/sgi-xp/xpc.h | 9 +-- drivers/misc/sgi-xp/xpc_channel.c | 112 +++++++++++++------------------------- drivers/misc/sgi-xp/xpc_main.c | 14 ++--- drivers/misc/sgi-xp/xpc_sn2.c | 64 ++++++++++------------ drivers/misc/sgi-xp/xpnet.c | 11 ++-- 7 files changed, 106 insertions(+), 171 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index 0f75592896d..43bf2470850 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -116,12 +116,6 @@ * The size of the payload is defined by the user via xpc_connect(). A user- * defined message resides in the payload area. * - * The user should have no dealings with the message header, but only the - * message's payload. When a message entry is allocated (via xpc_allocate()) - * a pointer to the payload area is returned and not the actual beginning of - * the XPC message. The user then constructs a message in the payload area - * and passes that pointer as an argument on xpc_send() or xpc_send_notify(). - * * The size of a message entry (within a message queue) must be a cacheline * sized multiple in order to facilitate the BTE transfer of messages from one * message queue to another. A macro, XPC_MSG_SIZE(), is provided for the user @@ -221,9 +215,10 @@ enum xp_retval { xpBteCopyError, /* 52: bte_copy() returned error */ xpSalError, /* 53: sn SAL error */ xpRsvdPageNotSet, /* 54: the reserved page is not set up */ + xpPayloadTooBig, /* 55: payload too large for message slot */ - xpUnsupported, /* 55: unsupported functionality or resource */ - xpUnknownReason /* 56: unknown reason - must be last in enum */ + xpUnsupported, /* 56: unsupported functionality or resource */ + xpUnknownReason /* 57: unknown reason - must be last in enum */ }; /* @@ -304,16 +299,15 @@ struct xpc_registration { #define XPC_CHANNEL_REGISTERED(_c) (xpc_registrations[_c].func != NULL) -/* the following are valid xpc_allocate() flags */ +/* the following are valid xpc_send() or xpc_send_notify() flags */ #define XPC_WAIT 0 /* wait flag */ #define XPC_NOWAIT 1 /* no wait flag */ struct xpc_interface { void (*connect) (int); void (*disconnect) (int); - enum xp_retval (*allocate) (short, int, u32, void **); - enum xp_retval (*send) (short, int, void *); - enum xp_retval (*send_notify) (short, int, void *, + enum xp_retval (*send) (short, int, u32, void *, u16); + enum xp_retval (*send_notify) (short, int, u32, void *, u16, xpc_notify_func, void *); void (*received) (short, int, void *); enum xp_retval (*partid_to_nasids) (short, void *); @@ -323,10 +317,9 @@ extern struct xpc_interface xpc_interface; extern void xpc_set_interface(void (*)(int), void (*)(int), - enum xp_retval (*)(short, int, u32, void **), - enum xp_retval (*)(short, int, void *), - enum xp_retval (*)(short, int, void *, - xpc_notify_func, void *), + enum xp_retval (*)(short, int, u32, void *, u16), + enum xp_retval (*)(short, int, u32, void *, u16, + xpc_notify_func, void *), void (*)(short, int, void *), enum xp_retval (*)(short, void *)); extern void xpc_clear_interface(void); @@ -336,22 +329,19 @@ extern enum xp_retval xpc_connect(int, xpc_channel_func, void *, u16, extern void xpc_disconnect(int); static inline enum xp_retval -xpc_allocate(short partid, int ch_number, u32 flags, void **payload) -{ - return xpc_interface.allocate(partid, ch_number, flags, payload); -} - -static inline enum xp_retval -xpc_send(short partid, int ch_number, void *payload) +xpc_send(short partid, int ch_number, u32 flags, void *payload, + u16 payload_size) { - return xpc_interface.send(partid, ch_number, payload); + return xpc_interface.send(partid, ch_number, flags, payload, + payload_size); } static inline enum xp_retval -xpc_send_notify(short partid, int ch_number, void *payload, - xpc_notify_func func, void *key) +xpc_send_notify(short partid, int ch_number, u32 flags, void *payload, + u16 payload_size, xpc_notify_func func, void *key) { - return xpc_interface.send_notify(partid, ch_number, payload, func, key); + return xpc_interface.send_notify(partid, ch_number, flags, payload, + payload_size, func, key); } static inline void diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c index 6f25613b27e..9c0ce2f15ff 100644 --- a/drivers/misc/sgi-xp/xp_main.c +++ b/drivers/misc/sgi-xp/xp_main.c @@ -58,10 +58,9 @@ xpc_notloaded(void) struct xpc_interface xpc_interface = { (void (*)(int))xpc_notloaded, (void (*)(int))xpc_notloaded, - (enum xp_retval(*)(short, int, u32, void **))xpc_notloaded, - (enum xp_retval(*)(short, int, void *))xpc_notloaded, - (enum xp_retval(*)(short, int, void *, xpc_notify_func, void *)) - xpc_notloaded, + (enum xp_retval(*)(short, int, u32, void *, u16))xpc_notloaded, + (enum xp_retval(*)(short, int, u32, void *, u16, xpc_notify_func, + void *))xpc_notloaded, (void (*)(short, int, void *))xpc_notloaded, (enum xp_retval(*)(short, void *))xpc_notloaded }; @@ -73,16 +72,14 @@ EXPORT_SYMBOL_GPL(xpc_interface); void xpc_set_interface(void (*connect) (int), void (*disconnect) (int), - enum xp_retval (*allocate) (short, int, u32, void **), - enum xp_retval (*send) (short, int, void *), - enum xp_retval (*send_notify) (short, int, void *, + enum xp_retval (*send) (short, int, u32, void *, u16), + enum xp_retval (*send_notify) (short, int, u32, void *, u16, xpc_notify_func, void *), void (*received) (short, int, void *), enum xp_retval (*partid_to_nasids) (short, void *)) { xpc_interface.connect = connect; xpc_interface.disconnect = disconnect; - xpc_interface.allocate = allocate; xpc_interface.send = send; xpc_interface.send_notify = send_notify; xpc_interface.received = received; @@ -98,13 +95,11 @@ xpc_clear_interface(void) { xpc_interface.connect = (void (*)(int))xpc_notloaded; xpc_interface.disconnect = (void (*)(int))xpc_notloaded; - xpc_interface.allocate = (enum xp_retval(*)(short, int, u32, - void **))xpc_notloaded; - xpc_interface.send = (enum xp_retval(*)(short, int, void *)) + xpc_interface.send = (enum xp_retval(*)(short, int, u32, void *, u16)) xpc_notloaded; - xpc_interface.send_notify = (enum xp_retval(*)(short, int, void *, - xpc_notify_func, - void *))xpc_notloaded; + xpc_interface.send_notify = (enum xp_retval(*)(short, int, u32, void *, + u16, xpc_notify_func, + void *))xpc_notloaded; xpc_interface.received = (void (*)(short, int, void *)) xpc_notloaded; xpc_interface.partid_to_nasids = (enum xp_retval(*)(short, void *)) diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 56bf5dcc391..6b622b091bd 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -624,9 +624,7 @@ extern void (*xpc_IPI_send_closereply) (struct xpc_channel *, unsigned long *); extern void (*xpc_IPI_send_openrequest) (struct xpc_channel *, unsigned long *); extern void (*xpc_IPI_send_openreply) (struct xpc_channel *, unsigned long *); -extern enum xp_retval (*xpc_allocate_msg) (struct xpc_channel *, u32, - struct xpc_msg **); -extern enum xp_retval (*xpc_send_msg) (struct xpc_channel *, struct xpc_msg *, +extern enum xp_retval (*xpc_send_msg) (struct xpc_channel *, u32, void *, u16, u8, xpc_notify_func, void *); extern void (*xpc_received_msg) (struct xpc_channel *, struct xpc_msg *); @@ -664,9 +662,8 @@ extern void *xpc_kzalloc_cacheline_aligned(size_t, gfp_t, void **); extern void xpc_initiate_connect(int); extern void xpc_initiate_disconnect(int); extern enum xp_retval xpc_allocate_msg_wait(struct xpc_channel *); -extern enum xp_retval xpc_initiate_allocate(short, int, u32, void **); -extern enum xp_retval xpc_initiate_send(short, int, void *); -extern enum xp_retval xpc_initiate_send_notify(short, int, void *, +extern enum xp_retval xpc_initiate_send(short, int, u32, void *, u16); +extern enum xp_retval xpc_initiate_send_notify(short, int, u32, void *, u16, xpc_notify_func, void *); extern void xpc_initiate_received(short, int, void *); extern void xpc_process_channel_activity(struct xpc_partition *); diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index 26c5e12c122..55182c8dd32 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -1192,87 +1192,54 @@ xpc_allocate_msg_wait(struct xpc_channel *ch) } /* - * Allocate an entry for a message from the message queue associated with the - * specified channel. NOTE that this routine can sleep waiting for a message - * entry to become available. To not sleep, pass in the XPC_NOWAIT flag. + * Send a message that contains the user's payload on the specified channel + * connected to the specified partition. * - * Arguments: + * NOTE that this routine can sleep waiting for a message entry to become + * available. To not sleep, pass in the XPC_NOWAIT flag. * - * partid - ID of partition to which the channel is connected. - * ch_number - channel #. - * flags - see xpc.h for valid flags. - * payload - address of the allocated payload area pointer (filled in on - * return) in which the user-defined message is constructed. - */ -enum xp_retval -xpc_initiate_allocate(short partid, int ch_number, u32 flags, void **payload) -{ - struct xpc_partition *part = &xpc_partitions[partid]; - enum xp_retval ret = xpUnknownReason; - struct xpc_msg *msg = NULL; - - DBUG_ON(partid < 0 || partid >= xp_max_npartitions); - DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); - - *payload = NULL; - - if (xpc_part_ref(part)) { - ret = xpc_allocate_msg(&part->channels[ch_number], flags, &msg); - xpc_part_deref(part); - - if (msg != NULL) - *payload = &msg->payload; - } - - return ret; -} - -/* - * Send a message previously allocated using xpc_initiate_allocate() on the - * specified channel connected to the specified partition. - * - * This routine will not wait for the message to be received, nor will - * notification be given when it does happen. Once this routine has returned - * the message entry allocated via xpc_initiate_allocate() is no longer - * accessable to the caller. - * - * This routine, although called by users, does not call xpc_part_ref() to - * ensure that the partition infrastructure is in place. It relies on the - * fact that we called xpc_msgqueue_ref() in xpc_allocate_msg(). + * Once sent, this routine will not wait for the message to be received, nor + * will notification be given when it does happen. * * Arguments: * * partid - ID of partition to which the channel is connected. * ch_number - channel # to send message on. - * payload - pointer to the payload area allocated via - * xpc_initiate_allocate(). + * flags - see xp.h for valid flags. + * payload - pointer to the payload which is to be sent. + * payload_size - size of the payload in bytes. */ enum xp_retval -xpc_initiate_send(short partid, int ch_number, void *payload) +xpc_initiate_send(short partid, int ch_number, u32 flags, void *payload, + u16 payload_size) { struct xpc_partition *part = &xpc_partitions[partid]; - struct xpc_msg *msg = XPC_MSG_ADDRESS(payload); - enum xp_retval ret; + enum xp_retval ret = xpUnknownReason; - dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *)msg, + dev_dbg(xpc_chan, "payload=0x%p, partid=%d, channel=%d\n", payload, partid, ch_number); DBUG_ON(partid < 0 || partid >= xp_max_npartitions); DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); - DBUG_ON(msg == NULL); + DBUG_ON(payload == NULL); - ret = xpc_send_msg(&part->channels[ch_number], msg, 0, NULL, NULL); + if (xpc_part_ref(part)) { + ret = xpc_send_msg(&part->channels[ch_number], flags, payload, + payload_size, 0, NULL, NULL); + xpc_part_deref(part); + } return ret; } /* - * Send a message previously allocated using xpc_initiate_allocate on the - * specified channel connected to the specified partition. + * Send a message that contains the user's payload on the specified channel + * connected to the specified partition. * - * This routine will not wait for the message to be sent. Once this routine - * has returned the message entry allocated via xpc_initiate_allocate() is no - * longer accessable to the caller. + * NOTE that this routine can sleep waiting for a message entry to become + * available. To not sleep, pass in the XPC_NOWAIT flag. + * + * This routine will not wait for the message to be sent or received. * * Once the remote end of the channel has received the message, the function * passed as an argument to xpc_initiate_send_notify() will be called. This @@ -1282,38 +1249,37 @@ xpc_initiate_send(short partid, int ch_number, void *payload) * * If this routine returns an error, the caller's function will NOT be called. * - * This routine, although called by users, does not call xpc_part_ref() to - * ensure that the partition infrastructure is in place. It relies on the - * fact that we called xpc_msgqueue_ref() in xpc_allocate_msg(). - * * Arguments: * * partid - ID of partition to which the channel is connected. * ch_number - channel # to send message on. - * payload - pointer to the payload area allocated via - * xpc_initiate_allocate(). + * flags - see xp.h for valid flags. + * payload - pointer to the payload which is to be sent. + * payload_size - size of the payload in bytes. * func - function to call with asynchronous notification of message * receipt. THIS FUNCTION MUST BE NON-BLOCKING. * key - user-defined key to be passed to the function when it's called. */ enum xp_retval -xpc_initiate_send_notify(short partid, int ch_number, void *payload, - xpc_notify_func func, void *key) +xpc_initiate_send_notify(short partid, int ch_number, u32 flags, void *payload, + u16 payload_size, xpc_notify_func func, void *key) { struct xpc_partition *part = &xpc_partitions[partid]; - struct xpc_msg *msg = XPC_MSG_ADDRESS(payload); - enum xp_retval ret; + enum xp_retval ret = xpUnknownReason; - dev_dbg(xpc_chan, "msg=0x%p, partid=%d, channel=%d\n", (void *)msg, + dev_dbg(xpc_chan, "payload=0x%p, partid=%d, channel=%d\n", payload, partid, ch_number); DBUG_ON(partid < 0 || partid >= xp_max_npartitions); DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); - DBUG_ON(msg == NULL); + DBUG_ON(payload == NULL); DBUG_ON(func == NULL); - ret = xpc_send_msg(&part->channels[ch_number], msg, XPC_N_CALL, - func, key); + if (xpc_part_ref(part)) { + ret = xpc_send_msg(&part->channels[ch_number], flags, payload, + payload_size, XPC_N_CALL, func, key); + xpc_part_deref(part); + } return ret; } @@ -1372,7 +1338,7 @@ xpc_deliver_msg(struct xpc_channel *ch) * partid - ID of partition to which the channel is connected. * ch_number - channel # message received on. * payload - pointer to the payload area allocated via - * xpc_initiate_allocate(). + * xpc_initiate_send() or xpc_initiate_send_notify(). */ void xpc_initiate_received(short partid, int ch_number, void *payload) diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index 4a6eb377475..aae90f5933b 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -217,12 +217,9 @@ void (*xpc_IPI_send_openrequest) (struct xpc_channel *ch, void (*xpc_IPI_send_openreply) (struct xpc_channel *ch, unsigned long *irq_flags); -enum xp_retval (*xpc_allocate_msg) (struct xpc_channel *ch, u32 flags, - struct xpc_msg **address_of_msg); - -enum xp_retval (*xpc_send_msg) (struct xpc_channel *ch, struct xpc_msg *msg, - u8 notify_type, xpc_notify_func func, - void *key); +enum xp_retval (*xpc_send_msg) (struct xpc_channel *ch, u32 flags, + void *payload, u16 payload_size, u8 notify_type, + xpc_notify_func func, void *key); void (*xpc_received_msg) (struct xpc_channel *ch, struct xpc_msg *msg); /* @@ -1286,9 +1283,8 @@ xpc_init(void) /* set the interface to point at XPC's functions */ xpc_set_interface(xpc_initiate_connect, xpc_initiate_disconnect, - xpc_initiate_allocate, xpc_initiate_send, - xpc_initiate_send_notify, xpc_initiate_received, - xpc_initiate_partid_to_nasids); + xpc_initiate_send, xpc_initiate_send_notify, + xpc_initiate_received, xpc_initiate_partid_to_nasids); return 0; diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index 7216df36bc7..db67d348b35 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -1532,18 +1532,6 @@ xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags, enum xp_retval ret; s64 put; - /* this reference will be dropped in xpc_send_msg_sn2() */ - xpc_msgqueue_ref(ch); - - if (ch->flags & XPC_C_DISCONNECTING) { - xpc_msgqueue_deref(ch); - return ch->reason; - } - if (!(ch->flags & XPC_C_CONNECTED)) { - xpc_msgqueue_deref(ch); - return xpNotConnected; - } - /* * Get the next available message entry from the local message queue. * If none are available, we'll make sure that we grab the latest @@ -1582,16 +1570,12 @@ xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags, if (ret == xpTimeout) xpc_IPI_send_local_msgrequest_sn2(ch); - if (flags & XPC_NOWAIT) { - xpc_msgqueue_deref(ch); + if (flags & XPC_NOWAIT) return xpNoWait; - } ret = xpc_allocate_msg_wait(ch); - if (ret != xpInterrupted && ret != xpTimeout) { - xpc_msgqueue_deref(ch); + if (ret != xpInterrupted && ret != xpTimeout) return ret; - } } /* get the message's address and initialize it */ @@ -1606,7 +1590,6 @@ xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags, (void *)msg, msg->number, ch->partid, ch->number); *address_of_msg = msg; - return xpSuccess; } @@ -1616,24 +1599,38 @@ xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags, * message is being sent to. */ static enum xp_retval -xpc_send_msg_sn2(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type, - xpc_notify_func func, void *key) +xpc_send_msg_sn2(struct xpc_channel *ch, u32 flags, void *payload, + u16 payload_size, u8 notify_type, xpc_notify_func func, + void *key) { enum xp_retval ret = xpSuccess; + struct xpc_msg *msg = msg; struct xpc_notify *notify = notify; - s64 put, msg_number = msg->number; + s64 msg_number; + s64 put; DBUG_ON(notify_type == XPC_N_CALL && func == NULL); - DBUG_ON((((u64)msg - (u64)ch->local_msgqueue) / ch->msg_size) != - msg_number % ch->local_nentries); - DBUG_ON(msg->flags & XPC_M_READY); + + if (XPC_MSG_SIZE(payload_size) > ch->msg_size) + return xpPayloadTooBig; + + xpc_msgqueue_ref(ch); if (ch->flags & XPC_C_DISCONNECTING) { - /* drop the reference grabbed in xpc_allocate_msg_sn2() */ - xpc_msgqueue_deref(ch); - return ch->reason; + ret = ch->reason; + goto out_1; + } + if (!(ch->flags & XPC_C_CONNECTED)) { + ret = xpNotConnected; + goto out_1; } + ret = xpc_allocate_msg_sn2(ch, flags, &msg); + if (ret != xpSuccess) + goto out_1; + + msg_number = msg->number; + if (notify_type != 0) { /* * Tell the remote side to send an ACK interrupt when the @@ -1663,13 +1660,12 @@ xpc_send_msg_sn2(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type, atomic_dec(&ch->n_to_notify); ret = ch->reason; } - - /* drop reference grabbed in xpc_allocate_msg_sn2() */ - xpc_msgqueue_deref(ch); - return ret; + goto out_1; } } + memcpy(&msg->payload, payload, payload_size); + msg->flags |= XPC_M_READY; /* @@ -1684,7 +1680,7 @@ xpc_send_msg_sn2(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type, if (put == msg_number) xpc_send_msgs_sn2(ch, put); - /* drop the reference grabbed in xpc_allocate_msg_sn2() */ +out_1: xpc_msgqueue_deref(ch); return ret; } @@ -1821,8 +1817,6 @@ xpc_init_sn2(void) xpc_IPI_send_openrequest = xpc_IPI_send_openrequest_sn2; xpc_IPI_send_openreply = xpc_IPI_send_openreply_sn2; - xpc_allocate_msg = xpc_allocate_msg_sn2; - xpc_send_msg = xpc_send_msg_sn2; xpc_received_msg = xpc_received_msg_sn2; } diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 9c540eb1847..f9356ba7315 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -438,7 +438,8 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct xpnet_pending_msg *queued_msg; enum xp_retval ret; - struct xpnet_message *msg; + u8 msg_buffer[XPNET_MSG_SIZE]; + struct xpnet_message *msg = (struct xpnet_message *)&msg_buffer[0]; u64 start_addr, end_addr; long dp; u8 second_mac_octet; @@ -524,11 +525,6 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) /* found a partition to send to */ - ret = xpc_allocate(dest_partid, XPC_NET_CHANNEL, - XPC_NOWAIT, (void **)&msg); - if (unlikely(ret != xpSuccess)) - continue; - msg->embedded_bytes = embedded_bytes; if (unlikely(embedded_bytes != 0)) { msg->version = XPNET_VERSION_EMBED; @@ -553,7 +549,8 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) atomic_inc(&queued_msg->use_count); - ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, msg, + ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, XPC_NOWAIT, + &msg, sizeof(msg) + embedded_bytes - 1, xpnet_send_completed, queued_msg); if (unlikely(ret != xpSuccess)) { atomic_dec(&queued_msg->use_count); -- cgit v1.2.3 From 6e41017aad9ed175ca51e4828eabc8c5cf5910be Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:09 -0700 Subject: sgi-xp: isolate activate IRQ's hardware specific components Isolate architecture specific code related to XPC's activate IRQ. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xpc.h | 14 ++- drivers/misc/sgi-xp/xpc_main.c | 96 ++++++---------- drivers/misc/sgi-xp/xpc_partition.c | 121 -------------------- drivers/misc/sgi-xp/xpc_sn2.c | 217 +++++++++++++++++++++++++++++++----- 4 files changed, 229 insertions(+), 219 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 6b622b091bd..1edf37512de 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -480,7 +480,7 @@ struct xpc_partition { u64 remote_amos_page_pa; /* phys addr of partition's amos page */ int remote_act_nasid; /* active part's act/deact nasid */ int remote_act_phys_cpuid; /* active part's act/deact phys cpuid */ - u32 act_IRQ_rcvd; /* IRQs since activation */ + u32 activate_IRQ_rcvd; /* IRQs since activation */ spinlock_t act_lock; /* protect updating of act_state */ u8 act_state; /* from XPC HB viewpoint */ u8 remote_vars_version; /* version# of partition's vars */ @@ -580,8 +580,8 @@ extern struct device *xpc_part; extern struct device *xpc_chan; extern int xpc_disengage_request_timelimit; extern int xpc_disengage_request_timedout; -extern atomic_t xpc_act_IRQ_rcvd; -extern wait_queue_head_t xpc_act_IRQ_wq; +extern atomic_t xpc_activate_IRQ_rcvd; +extern wait_queue_head_t xpc_activate_IRQ_wq; extern void *xpc_heartbeating_to_mask; extern irqreturn_t xpc_notify_IRQ_handler(int, void *); extern void xpc_dropped_IPI_check(struct xpc_partition *); @@ -601,7 +601,7 @@ extern u64 (*xpc_get_IPI_flags) (struct xpc_partition *); extern struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *); extern void (*xpc_initiate_partition_activation) (struct xpc_rsvd_page *, u64, int); -extern void (*xpc_process_act_IRQ_rcvd) (int); +extern void (*xpc_process_activate_IRQ_rcvd) (int); extern enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *); extern void (*xpc_teardown_infrastructure) (struct xpc_partition *); extern void (*xpc_mark_partition_engaged) (struct xpc_partition *); @@ -629,10 +629,12 @@ extern enum xp_retval (*xpc_send_msg) (struct xpc_channel *, u32, void *, u16, extern void (*xpc_received_msg) (struct xpc_channel *, struct xpc_msg *); /* found in xpc_sn2.c */ -extern void xpc_init_sn2(void); +extern int xpc_init_sn2(void); +extern void xpc_exit_sn2(void); /* found in xpc_uv.c */ extern void xpc_init_uv(void); +extern void xpc_exit_uv(void); /* found in xpc_partition.c */ extern int xpc_exiting; @@ -646,7 +648,7 @@ extern void *xpc_kmalloc_cacheline_aligned(size_t, gfp_t, void **); extern struct xpc_rsvd_page *xpc_setup_rsvd_page(void); extern void xpc_allow_IPI_ops(void); extern void xpc_restrict_IPI_ops(void); -extern int xpc_identify_act_IRQ_sender(void); +extern int xpc_identify_activate_IRQ_sender(void); extern int xpc_partition_disengaged(struct xpc_partition *); extern enum xp_retval xpc_mark_partition_active(struct xpc_partition *); extern void xpc_mark_partition_inactive(struct xpc_partition *); diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index aae90f5933b..8780d5d00f6 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -147,11 +147,11 @@ static struct ctl_table_header *xpc_sysctl; /* non-zero if any remote partition disengage request was timed out */ int xpc_disengage_request_timedout; -/* #of IRQs received */ -atomic_t xpc_act_IRQ_rcvd; +/* #of activate IRQs received */ +atomic_t xpc_activate_IRQ_rcvd = ATOMIC_INIT(0); /* IRQ handler notifies this wait queue on receipt of an IRQ */ -DECLARE_WAIT_QUEUE_HEAD(xpc_act_IRQ_wq); +DECLARE_WAIT_QUEUE_HEAD(xpc_activate_IRQ_wq); static unsigned long xpc_hb_check_timeout; static struct timer_list xpc_hb_timer; @@ -190,7 +190,7 @@ struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *ch); void (*xpc_initiate_partition_activation) (struct xpc_rsvd_page *remote_rp, u64 remote_rp_pa, int nasid); -void (*xpc_process_act_IRQ_rcvd) (int n_IRQs_expected); +void (*xpc_process_activate_IRQ_rcvd) (int n_IRQs_expected); enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *part); void (*xpc_teardown_infrastructure) (struct xpc_partition *part); @@ -238,17 +238,6 @@ xpc_timeout_partition_disengage_request(unsigned long data) DBUG_ON(xpc_partition_engaged(1UL << XPC_PARTID(part)) != 0); } -/* - * Notify the heartbeat check thread that an IRQ has been received. - */ -static irqreturn_t -xpc_act_IRQ_handler(int irq, void *dev_id) -{ - atomic_inc(&xpc_act_IRQ_rcvd); - wake_up_interruptible(&xpc_act_IRQ_wq); - return IRQ_HANDLED; -} - /* * Timer to produce the heartbeat. The timer structures function is * already set when this is initially called. A tunable is used to @@ -260,7 +249,7 @@ xpc_hb_beater(unsigned long dummy) xpc_increment_heartbeat(); if (time_is_before_eq_jiffies(xpc_hb_check_timeout)) - wake_up_interruptible(&xpc_act_IRQ_wq); + wake_up_interruptible(&xpc_activate_IRQ_wq); xpc_hb_timer.expires = jiffies + (xpc_hb_interval * HZ); add_timer(&xpc_hb_timer); @@ -306,7 +295,7 @@ xpc_hb_checker(void *ignore) dev_dbg(xpc_part, "woke up with %d ticks rem; %d IRQs have " "been received\n", (int)(xpc_hb_check_timeout - jiffies), - atomic_read(&xpc_act_IRQ_rcvd) - last_IRQ_count); + atomic_read(&xpc_activate_IRQ_rcvd) - last_IRQ_count); /* checking of remote heartbeats is skewed by IRQ handling */ if (time_is_before_eq_jiffies(xpc_hb_check_timeout)) { @@ -322,15 +311,15 @@ xpc_hb_checker(void *ignore) } /* check for outstanding IRQs */ - new_IRQ_count = atomic_read(&xpc_act_IRQ_rcvd); + new_IRQ_count = atomic_read(&xpc_activate_IRQ_rcvd); if (last_IRQ_count < new_IRQ_count || force_IRQ != 0) { force_IRQ = 0; dev_dbg(xpc_part, "found an IRQ to process; will be " "resetting xpc_hb_check_timeout\n"); - xpc_process_act_IRQ_rcvd(new_IRQ_count - - last_IRQ_count); + xpc_process_activate_IRQ_rcvd(new_IRQ_count - + last_IRQ_count); last_IRQ_count = new_IRQ_count; xpc_hb_check_timeout = jiffies + @@ -338,9 +327,9 @@ xpc_hb_checker(void *ignore) } /* wait for IRQ or timeout */ - (void)wait_event_interruptible(xpc_act_IRQ_wq, - (last_IRQ_count < - atomic_read(&xpc_act_IRQ_rcvd) + (void)wait_event_interruptible(xpc_activate_IRQ_wq, + (last_IRQ_count < atomic_read( + &xpc_activate_IRQ_rcvd) || time_is_before_eq_jiffies( xpc_hb_check_timeout) || xpc_exiting)); @@ -884,10 +873,7 @@ xpc_do_exit(enum xp_retval reason) * the heartbeat checker thread in case it's sleeping. */ xpc_exiting = 1; - wake_up_interruptible(&xpc_act_IRQ_wq); - - /* ignore all incoming interrupts */ - free_irq(SGI_XPC_ACTIVATE, NULL); + wake_up_interruptible(&xpc_activate_IRQ_wq); /* wait for the discovery thread to exit */ wait_for_completion(&xpc_discovery_exited); @@ -968,9 +954,6 @@ xpc_do_exit(enum xp_retval reason) (void)unregister_reboot_notifier(&xpc_reboot_notifier); } - /* close down protections for IPI operations */ - xpc_restrict_IPI_ops(); - /* clear the interface to XPC's functions */ xpc_clear_interface(); @@ -979,6 +962,11 @@ xpc_do_exit(enum xp_retval reason) kfree(xpc_partitions); kfree(xpc_remote_copy_buffer_base); + + if (is_shub()) + xpc_exit_sn2(); + else + xpc_exit_uv(); } /* @@ -1144,7 +1132,9 @@ xpc_init(void) if (xp_max_npartitions != 64) return -EINVAL; - xpc_init_sn2(); + ret = xpc_init_sn2(); + if (ret != 0) + return ret; } else if (is_uv()) { xpc_init_uv(); @@ -1163,7 +1153,8 @@ xpc_init(void) &xpc_remote_copy_buffer_base); if (xpc_remote_copy_buffer == NULL) { dev_err(xpc_part, "can't get memory for remote copy buffer\n"); - return -ENOMEM; + ret = -ENOMEM; + goto out_1; } xpc_partitions = kzalloc(sizeof(struct xpc_partition) * @@ -1171,7 +1162,7 @@ xpc_init(void) if (xpc_partitions == NULL) { dev_err(xpc_part, "can't get memory for partition structure\n"); ret = -ENOMEM; - goto out_1; + goto out_2; } /* @@ -1187,7 +1178,7 @@ xpc_init(void) DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part)); - part->act_IRQ_rcvd = 0; + part->activate_IRQ_rcvd = 0; spin_lock_init(&part->act_lock); part->act_state = XPC_P_INACTIVE; XPC_SET_REASON(part, 0, 0); @@ -1204,33 +1195,6 @@ xpc_init(void) xpc_sysctl = register_sysctl_table(xpc_sys_dir); - /* - * Open up protections for IPI operations (and AMO operations on - * Shub 1.1 systems). - */ - xpc_allow_IPI_ops(); - - /* - * Interrupts being processed will increment this atomic variable and - * awaken the heartbeat thread which will process the interrupts. - */ - atomic_set(&xpc_act_IRQ_rcvd, 0); - - /* - * This is safe to do before the xpc_hb_checker thread has started - * because the handler releases a wait queue. If an interrupt is - * received before the thread is waiting, it will not go to sleep, - * but rather immediately process the interrupt. - */ - ret = request_irq(SGI_XPC_ACTIVATE, xpc_act_IRQ_handler, 0, - "xpc hb", NULL); - if (ret != 0) { - dev_err(xpc_part, "can't register ACTIVATE IRQ handler, " - "errno=%d\n", -ret); - ret = -EBUSY; - goto out_2; - } - /* * Fill the partition reserved page with the information needed by * other partitions to discover we are alive and establish initial @@ -1296,14 +1260,16 @@ out_4: (void)unregister_die_notifier(&xpc_die_notifier); (void)unregister_reboot_notifier(&xpc_reboot_notifier); out_3: - free_irq(SGI_XPC_ACTIVATE, NULL); -out_2: - xpc_restrict_IPI_ops(); if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); kfree(xpc_partitions); -out_1: +out_2: kfree(xpc_remote_copy_buffer_base); +out_1: + if (is_shub()) + xpc_exit_sn2(); + else + xpc_exit_uv(); return ret; } diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 90ec5ca8c9a..bf9b1193bd2 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -29,16 +29,6 @@ /* XPC is exiting flag */ int xpc_exiting; -/* SH_IPI_ACCESS shub register value on startup */ -static u64 xpc_sh1_IPI_access; -static u64 xpc_sh2_IPI_access0; -static u64 xpc_sh2_IPI_access1; -static u64 xpc_sh2_IPI_access2; -static u64 xpc_sh2_IPI_access3; - -/* original protection values for each node */ -u64 xpc_prot_vec[MAX_NUMNODES]; - /* this partition's reserved page pointers */ struct xpc_rsvd_page *xpc_rsvd_page; static u64 *xpc_part_nasids; @@ -210,117 +200,6 @@ xpc_setup_rsvd_page(void) return rp; } -/* - * Change protections to allow IPI operations (and AMO operations on - * Shub 1.1 systems). - */ -void -xpc_allow_IPI_ops(void) -{ - int node; - int nasid; - - /* >>> Change SH_IPI_ACCESS code to use SAL call once it is available */ - - if (is_shub2()) { - xpc_sh2_IPI_access0 = - (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS0)); - xpc_sh2_IPI_access1 = - (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS1)); - xpc_sh2_IPI_access2 = - (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS2)); - xpc_sh2_IPI_access3 = - (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS3)); - - for_each_online_node(node) { - nasid = cnodeid_to_nasid(node); - HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), - -1UL); - HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), - -1UL); - HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), - -1UL); - HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), - -1UL); - } - - } else { - xpc_sh1_IPI_access = - (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH1_IPI_ACCESS)); - - for_each_online_node(node) { - nasid = cnodeid_to_nasid(node); - HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), - -1UL); - - /* - * Since the BIST collides with memory operations on - * SHUB 1.1 sn_change_memprotect() cannot be used. - */ - if (enable_shub_wars_1_1()) { - /* open up everything */ - xpc_prot_vec[node] = (u64)HUB_L((u64 *) - GLOBAL_MMR_ADDR - (nasid, - SH1_MD_DQLP_MMR_DIR_PRIVEC0)); - HUB_S((u64 *) - GLOBAL_MMR_ADDR(nasid, - SH1_MD_DQLP_MMR_DIR_PRIVEC0), - -1UL); - HUB_S((u64 *) - GLOBAL_MMR_ADDR(nasid, - SH1_MD_DQRP_MMR_DIR_PRIVEC0), - -1UL); - } - } - } -} - -/* - * Restrict protections to disallow IPI operations (and AMO operations on - * Shub 1.1 systems). - */ -void -xpc_restrict_IPI_ops(void) -{ - int node; - int nasid; - - /* >>> Change SH_IPI_ACCESS code to use SAL call once it is available */ - - if (is_shub2()) { - - for_each_online_node(node) { - nasid = cnodeid_to_nasid(node); - HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), - xpc_sh2_IPI_access0); - HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), - xpc_sh2_IPI_access1); - HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), - xpc_sh2_IPI_access2); - HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), - xpc_sh2_IPI_access3); - } - - } else { - - for_each_online_node(node) { - nasid = cnodeid_to_nasid(node); - HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), - xpc_sh1_IPI_access); - - if (enable_shub_wars_1_1()) { - HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, - SH1_MD_DQLP_MMR_DIR_PRIVEC0), - xpc_prot_vec[node]); - HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, - SH1_MD_DQRP_MMR_DIR_PRIVEC0), - xpc_prot_vec[node]); - } - } - } -} - /* * Get a copy of a portion of the remote partition's rsvd page. * diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index db67d348b35..4659f6cb885 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -22,6 +22,87 @@ static struct xpc_vars_sn2 *xpc_vars; /* >>> Add _sn2 suffix? */ static struct xpc_vars_part_sn2 *xpc_vars_part; /* >>> Add _sn2 suffix? */ +/* SH_IPI_ACCESS shub register value on startup */ +static u64 xpc_sh1_IPI_access; +static u64 xpc_sh2_IPI_access0; +static u64 xpc_sh2_IPI_access1; +static u64 xpc_sh2_IPI_access2; +static u64 xpc_sh2_IPI_access3; + +/* + * Change protections to allow IPI operations. + */ +static void +xpc_allow_IPI_ops_sn2(void) +{ + int node; + int nasid; + + /* >>> The following should get moved into SAL. */ + if (is_shub2()) { + xpc_sh2_IPI_access0 = + (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS0)); + xpc_sh2_IPI_access1 = + (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS1)); + xpc_sh2_IPI_access2 = + (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS2)); + xpc_sh2_IPI_access3 = + (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS3)); + + for_each_online_node(node) { + nasid = cnodeid_to_nasid(node); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), + -1UL); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), + -1UL); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), + -1UL); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), + -1UL); + } + } else { + xpc_sh1_IPI_access = + (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH1_IPI_ACCESS)); + + for_each_online_node(node) { + nasid = cnodeid_to_nasid(node); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), + -1UL); + } + } +} + +/* + * Restrict protections to disallow IPI operations. + */ +static void +xpc_disallow_IPI_ops_sn2(void) +{ + int node; + int nasid; + + /* >>> The following should get moved into SAL. */ + if (is_shub2()) { + for_each_online_node(node) { + nasid = cnodeid_to_nasid(node); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), + xpc_sh2_IPI_access0); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), + xpc_sh2_IPI_access1); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), + xpc_sh2_IPI_access2); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), + xpc_sh2_IPI_access3); + } + } else { + for_each_online_node(node) { + nasid = cnodeid_to_nasid(node); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), + xpc_sh1_IPI_access); + } + } +} + /* * The following set of macros and functions are used for the sending and * receiving of IPIs (also known as IRQs). There are two flavors of IPIs, @@ -73,6 +154,17 @@ xpc_IPI_init_sn2(int index) * IPIs associated with SGI_XPC_ACTIVATE IRQ. */ +/* + * Notify the heartbeat check thread that an activate IRQ has been received. + */ +static irqreturn_t +xpc_handle_activate_IRQ_sn2(int irq, void *dev_id) +{ + atomic_inc(&xpc_activate_IRQ_rcvd); + wake_up_interruptible(&xpc_activate_IRQ_wq); + return IRQ_HANDLED; +} + /* * Flag the appropriate AMO variable and send an IPI to the specified node. */ @@ -100,8 +192,8 @@ xpc_activate_IRQ_send_local_sn2(int from_nasid) /* fake the sending and receipt of an activate IRQ from remote nasid */ FETCHOP_STORE_OP(TO_AMO((u64)&amos[w_index].variable), FETCHOP_OR, (1UL << b_index)); - atomic_inc(&xpc_act_IRQ_rcvd); - wake_up_interruptible(&xpc_act_IRQ_wq); + atomic_inc(&xpc_activate_IRQ_rcvd); + wake_up_interruptible(&xpc_activate_IRQ_wq); } static void @@ -383,11 +475,65 @@ xpc_clear_partition_disengage_request_sn2(u64 partid_mask) ~partid_mask); } +/* original protection values for each node */ +static u64 xpc_prot_vec_sn2[MAX_NUMNODES]; + +/* + * Change protections to allow AMO operations on non-Shub 1.1 systems. + */ +static enum xp_retval +xpc_allow_AMO_ops_sn2(AMO_t *amos_page) +{ + u64 nasid_array = 0; + int ret; + + /* + * On SHUB 1.1, we cannot call sn_change_memprotect() since the BIST + * collides with memory operations. On those systems we call + * xpc_allow_AMO_ops_shub_wars_1_1_sn2() instead. + */ + if (!enable_shub_wars_1_1()) { + ret = sn_change_memprotect(ia64_tpa((u64)amos_page), PAGE_SIZE, + SN_MEMPROT_ACCESS_CLASS_1, + &nasid_array); + if (ret != 0) + return xpSalError; + } + return xpSuccess; +} + +/* + * Change protections to allow AMO operations on Shub 1.1 systems. + */ +static void +xpc_allow_AMO_ops_shub_wars_1_1_sn2(void) +{ + int node; + int nasid; + + if (!enable_shub_wars_1_1()) + return; + + for_each_online_node(node) { + nasid = cnodeid_to_nasid(node); + /* save current protection values */ + xpc_prot_vec_sn2[node] = + (u64)HUB_L((u64 *)GLOBAL_MMR_ADDR(nasid, + SH1_MD_DQLP_MMR_DIR_PRIVEC0)); + /* open up everything */ + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, + SH1_MD_DQLP_MMR_DIR_PRIVEC0), + -1UL); + HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, + SH1_MD_DQRP_MMR_DIR_PRIVEC0), + -1UL); + } +} + static enum xp_retval xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) { AMO_t *amos_page; - u64 nasid_array = 0; int i; int ret; @@ -421,21 +567,15 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) } /* - * Open up AMO-R/W to cpu. This is done for Shub 1.1 systems - * when xpc_allow_IPI_ops() is called via xpc_hb_init(). + * Open up AMO-R/W to cpu. This is done on Shub 1.1 systems + * when xpc_allow_AMO_ops_shub_wars_1_1_sn2() is called. */ - if (!enable_shub_wars_1_1()) { - ret = sn_change_memprotect(ia64_tpa((u64)amos_page), - PAGE_SIZE, - SN_MEMPROT_ACCESS_CLASS_1, - &nasid_array); - if (ret != 0) { - dev_err(xpc_part, "can't change memory " - "protections\n"); - uncached_free_page(__IA64_UNCACHED_OFFSET | - TO_PHYS((u64)amos_page), 1); - return xpSalError; - } + ret = xpc_allow_AMO_ops_sn2(amos_page); + if (ret != xpSuccess) { + dev_err(xpc_part, "can't allow AMO operations\n"); + uncached_free_page(__IA64_UNCACHED_OFFSET | + TO_PHYS((u64)amos_page), 1); + return ret; } } @@ -656,7 +796,7 @@ xpc_update_partition_info_sn2(struct xpc_partition *part, u8 remote_rp_version, * initialized reserved page. */ static void -xpc_identify_act_IRQ_req_sn2(int nasid) +xpc_identify_activate_IRQ_req_sn2(int nasid) { struct xpc_rsvd_page *remote_rp; struct xpc_vars_sn2 *remote_vars; @@ -702,10 +842,10 @@ xpc_identify_act_IRQ_req_sn2(int nasid) return; } - part->act_IRQ_rcvd++; + part->activate_IRQ_rcvd++; dev_dbg(xpc_part, "partid for nasid %d is %d; IRQs = %d; HB = " - "%ld:0x%lx\n", (int)nasid, (int)partid, part->act_IRQ_rcvd, + "%ld:0x%lx\n", (int)nasid, (int)partid, part->activate_IRQ_rcvd, remote_vars->heartbeat, remote_vars->heartbeating_to_mask[0]); if (xpc_partition_disengaged(part) && @@ -831,7 +971,7 @@ xpc_identify_act_IRQ_req_sn2(int nasid) * Return #of IRQs detected. */ int -xpc_identify_act_IRQ_sender_sn2(void) +xpc_identify_activate_IRQ_sender_sn2(void) { int word, bit; u64 nasid_mask; @@ -872,7 +1012,7 @@ xpc_identify_act_IRQ_sender_sn2(void) nasid = XPC_NASID_FROM_W_B(word, bit); dev_dbg(xpc_part, "interrupt from nasid %ld\n", nasid); - xpc_identify_act_IRQ_req_sn2(nasid); + xpc_identify_activate_IRQ_req_sn2(nasid); } } } @@ -880,14 +1020,14 @@ xpc_identify_act_IRQ_sender_sn2(void) } static void -xpc_process_act_IRQ_rcvd_sn2(int n_IRQs_expected) +xpc_process_activate_IRQ_rcvd_sn2(int n_IRQs_expected) { int n_IRQs_detected; - n_IRQs_detected = xpc_identify_act_IRQ_sender_sn2(); + n_IRQs_detected = xpc_identify_activate_IRQ_sender_sn2(); if (n_IRQs_detected < n_IRQs_expected) { /* retry once to help avoid missing AMO */ - (void)xpc_identify_act_IRQ_sender_sn2(); + (void)xpc_identify_activate_IRQ_sender_sn2(); } } @@ -1775,9 +1915,11 @@ xpc_received_msg_sn2(struct xpc_channel *ch, struct xpc_msg *msg) xpc_acknowledge_msgs_sn2(ch, get, msg->flags); } -void +int xpc_init_sn2(void) { + int ret; + xpc_rsvd_page_init = xpc_rsvd_page_init_sn2; xpc_increment_heartbeat = xpc_increment_heartbeat_sn2; xpc_offline_heartbeat = xpc_offline_heartbeat_sn2; @@ -1788,7 +1930,7 @@ xpc_init_sn2(void) xpc_initiate_partition_activation = xpc_initiate_partition_activation_sn2; - xpc_process_act_IRQ_rcvd = xpc_process_act_IRQ_rcvd_sn2; + xpc_process_activate_IRQ_rcvd = xpc_process_activate_IRQ_rcvd_sn2; xpc_setup_infrastructure = xpc_setup_infrastructure_sn2; xpc_teardown_infrastructure = xpc_teardown_infrastructure_sn2; xpc_make_first_contact = xpc_make_first_contact_sn2; @@ -1819,9 +1961,30 @@ xpc_init_sn2(void) xpc_send_msg = xpc_send_msg_sn2; xpc_received_msg = xpc_received_msg_sn2; + + /* open up protections for IPI and [potentially] AMO operations */ + xpc_allow_IPI_ops_sn2(); + xpc_allow_AMO_ops_shub_wars_1_1_sn2(); + + /* + * This is safe to do before the xpc_hb_checker thread has started + * because the handler releases a wait queue. If an interrupt is + * received before the thread is waiting, it will not go to sleep, + * but rather immediately process the interrupt. + */ + ret = request_irq(SGI_XPC_ACTIVATE, xpc_handle_activate_IRQ_sn2, 0, + "xpc hb", NULL); + if (ret != 0) { + dev_err(xpc_part, "can't register ACTIVATE IRQ handler, " + "errno=%d\n", -ret); + xpc_disallow_IPI_ops_sn2(); + } + return ret; } void xpc_exit_sn2(void) { + free_irq(SGI_XPC_ACTIVATE, NULL); + xpc_disallow_IPI_ops_sn2(); } -- cgit v1.2.3 From a47d5dac9d8481766382f8cf1483dd581df38b99 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:09 -0700 Subject: sgi-xp: isolate additional sn2 specific code Move additional sn2 specific code into xpc_sn2.c. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xpc.h | 173 ++++---- drivers/misc/sgi-xp/xpc_channel.c | 214 +-------- drivers/misc/sgi-xp/xpc_main.c | 278 ++++-------- drivers/misc/sgi-xp/xpc_partition.c | 59 ++- drivers/misc/sgi-xp/xpc_sn2.c | 851 +++++++++++++++++++++++------------- drivers/misc/sgi-xp/xpc_uv.c | 15 +- 6 files changed, 784 insertions(+), 806 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 1edf37512de..b04cfbed958 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -122,9 +122,6 @@ struct xpc_rsvd_page { #define XPC_RP_VERSION _XPC_VERSION(2, 0) /* version 2.0 of the reserved page */ -#define XPC_SUPPORTS_RP_STAMP(_version) \ - (_version >= _XPC_VERSION(1, 1)) - /* * Define the structures by which XPC variables can be exported to other * partitions. (There are two: struct xpc_vars and struct xpc_vars_part) @@ -144,8 +141,8 @@ struct xpc_vars_sn2 { u64 heartbeat; DECLARE_BITMAP(heartbeating_to_mask, XP_MAX_NPARTITIONS_SN2); u64 heartbeat_offline; /* if 0, heartbeat should be changing */ - int act_nasid; - int act_phys_cpuid; + int activate_IRQ_nasid; + int activate_IRQ_phys_cpuid; u64 vars_part_pa; u64 amos_page_pa; /* paddr of page of AMOs from MSPEC driver */ AMO_t *amos_page; /* vaddr of page of AMOs from MSPEC driver */ @@ -153,9 +150,6 @@ struct xpc_vars_sn2 { #define XPC_V_VERSION _XPC_VERSION(3, 1) /* version 3.1 of the cross vars */ -#define XPC_SUPPORTS_DISENGAGE_REQUEST(_version) \ - (_version >= _XPC_VERSION(3, 1)) - /* * The following pertains to ia64-sn2 only. * @@ -167,14 +161,14 @@ struct xpc_vars_sn2 { * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64 * AMO variables (based on XP_MAX_NPARTITIONS_SN2) to identify the senders of * NOTIFY IRQs, 128 AMO variables (based on XP_NASID_MASK_WORDS) to identify - * the senders of ACTIVATE IRQs, and 2 AMO variables to identify which remote + * the senders of ACTIVATE IRQs, 1 AMO variable to identify which remote * partitions (i.e., XPCs) consider themselves currently engaged with the - * local XPC. + * local XPC and 1 AMO variable to request partition deactivation. */ #define XPC_NOTIFY_IRQ_AMOS 0 #define XPC_ACTIVATE_IRQ_AMOS (XPC_NOTIFY_IRQ_AMOS + XP_MAX_NPARTITIONS_SN2) #define XPC_ENGAGED_PARTITIONS_AMO (XPC_ACTIVATE_IRQ_AMOS + XP_NASID_MASK_WORDS) -#define XPC_DISENGAGE_REQUEST_AMO (XPC_ENGAGED_PARTITIONS_AMO + 1) +#define XPC_DEACTIVATE_REQUEST_AMO (XPC_ENGAGED_PARTITIONS_AMO + 1) /* * The following structure describes the per partition specific variables. @@ -369,6 +363,23 @@ struct xpc_notify { * new messages, by the clearing of the message flags of the acknowledged * messages. */ +struct xpc_channel_sn2 { + + /* various flavors of local and remote Get/Put values */ + + struct xpc_gp *local_GP; /* local Get/Put values */ + struct xpc_gp remote_GP; /* remote Get/Put values */ + struct xpc_gp w_local_GP; /* working local Get/Put values */ + struct xpc_gp w_remote_GP; /* working remote Get/Put values */ + s64 next_msg_to_pull; /* Put value of next msg to pull */ + + struct mutex msg_to_pull_mutex; /* next msg to pull serialization */ +}; + +struct xpc_channel_uv { + /* >>> code is coming */ +}; + struct xpc_channel { short partid; /* ID of remote partition connected */ spinlock_t lock; /* lock for updating this structure */ @@ -407,20 +418,11 @@ struct xpc_channel { xpc_channel_func func; /* user's channel function */ void *key; /* pointer to user's key */ - struct mutex msg_to_pull_mutex; /* next msg to pull serialization */ struct completion wdisconnect_wait; /* wait for channel disconnect */ struct xpc_openclose_args *local_openclose_args; /* args passed on */ /* opening or closing of channel */ - /* various flavors of local and remote Get/Put values */ - - struct xpc_gp *local_GP; /* local Get/Put values */ - struct xpc_gp remote_GP; /* remote Get/Put values */ - struct xpc_gp w_local_GP; /* working local Get/Put values */ - struct xpc_gp w_remote_GP; /* working remote Get/Put values */ - s64 next_msg_to_pull; /* Put value of next msg to pull */ - /* kthread management related fields */ atomic_t kthreads_assigned; /* #of kthreads assigned to channel */ @@ -431,6 +433,11 @@ struct xpc_channel { wait_queue_head_t idle_wq; /* idle kthread wait queue */ + union { + struct xpc_channel_sn2 sn2; + struct xpc_channel_uv uv; + } sn; + } ____cacheline_aligned; /* struct xpc_channel flags */ @@ -467,6 +474,40 @@ struct xpc_channel { * for each partition (a partition will never utilize the structure that * represents itself). */ + +struct xpc_partition_sn2 { + u64 remote_amos_page_pa; /* phys addr of partition's amos page */ + int activate_IRQ_nasid; /* active partition's act/deact nasid */ + int activate_IRQ_phys_cpuid; /* active part's act/deact phys cpuid */ + + u64 remote_vars_pa; /* phys addr of partition's vars */ + u64 remote_vars_part_pa; /* phys addr of partition's vars part */ + u8 remote_vars_version; /* version# of partition's vars */ + + void *local_GPs_base; /* base address of kmalloc'd space */ + struct xpc_gp *local_GPs; /* local Get/Put values */ + void *remote_GPs_base; /* base address of kmalloc'd space */ + struct xpc_gp *remote_GPs; /* copy of remote partition's local */ + /* Get/Put values */ + u64 remote_GPs_pa; /* phys address of remote partition's local */ + /* Get/Put values */ + + u64 remote_openclose_args_pa; /* phys addr of remote's args */ + + int remote_IPI_nasid; /* nasid of where to send IPIs */ + int remote_IPI_phys_cpuid; /* phys CPU ID of where to send IPIs */ + char IPI_owner[8]; /* IPI owner's name */ + + AMO_t *remote_IPI_amo_va; /* address of remote IPI AMO_t structure */ + AMO_t *local_IPI_amo_va; /* address of IPI AMO_t structure */ + + struct timer_list dropped_notify_IRQ_timer; /* dropped IRQ timer */ +}; + +struct xpc_partition_uv { + /* >>> code is coming */ +}; + struct xpc_partition { /* XPC HB infrastructure */ @@ -474,22 +515,15 @@ struct xpc_partition { u8 remote_rp_version; /* version# of partition's rsvd pg */ unsigned long remote_rp_stamp; /* time when rsvd pg was initialized */ u64 remote_rp_pa; /* phys addr of partition's rsvd pg */ - u64 remote_vars_pa; /* phys addr of partition's vars */ - u64 remote_vars_part_pa; /* phys addr of partition's vars part */ u64 last_heartbeat; /* HB at last read */ - u64 remote_amos_page_pa; /* phys addr of partition's amos page */ - int remote_act_nasid; /* active part's act/deact nasid */ - int remote_act_phys_cpuid; /* active part's act/deact phys cpuid */ u32 activate_IRQ_rcvd; /* IRQs since activation */ spinlock_t act_lock; /* protect updating of act_state */ u8 act_state; /* from XPC HB viewpoint */ - u8 remote_vars_version; /* version# of partition's vars */ enum xp_retval reason; /* reason partition is deactivating */ int reason_line; /* line# deactivation initiated from */ - int reactivate_nasid; /* nasid in partition to reactivate */ - unsigned long disengage_request_timeout; /* timeout in jiffies */ - struct timer_list disengage_request_timer; + unsigned long disengage_timeout; /* timeout in jiffies */ + struct timer_list disengage_timer; /* XPC infrastructure referencing and teardown control */ @@ -502,14 +536,6 @@ struct xpc_partition { atomic_t nchannels_engaged; /* #of channels engaged with remote part */ struct xpc_channel *channels; /* array of channel structures */ - void *local_GPs_base; /* base address of kmalloc'd space */ - struct xpc_gp *local_GPs; /* local Get/Put values */ - void *remote_GPs_base; /* base address of kmalloc'd space */ - struct xpc_gp *remote_GPs; /* copy of remote partition's local */ - /* Get/Put values */ - u64 remote_GPs_pa; /* phys address of remote partition's local */ - /* Get/Put values */ - /* fields used to pass args when opening or closing a channel */ void *local_openclose_args_base; /* base address of kmalloc'd space */ @@ -517,19 +543,10 @@ struct xpc_partition { void *remote_openclose_args_base; /* base address of kmalloc'd space */ struct xpc_openclose_args *remote_openclose_args; /* copy of remote's */ /* args */ - u64 remote_openclose_args_pa; /* phys addr of remote's args */ /* IPI sending, receiving and handling related fields */ - int remote_IPI_nasid; /* nasid of where to send IPIs */ - int remote_IPI_phys_cpuid; /* phys CPU ID of where to send IPIs */ - AMO_t *remote_IPI_amo_va; /* address of remote IPI AMO_t structure */ - - AMO_t *local_IPI_amo_va; /* address of IPI AMO_t structure */ u64 local_IPI_amo; /* IPI amo flags yet to be handled */ - char IPI_owner[8]; /* IPI owner's name */ - struct timer_list dropped_IPI_timer; /* dropped IPI timer */ - spinlock_t IPI_lock; /* IPI handler lock */ /* channel manager related fields */ @@ -537,6 +554,11 @@ struct xpc_partition { atomic_t channel_mgr_requests; /* #of requests to activate chan mgr */ wait_queue_head_t channel_mgr_wq; /* channel mgr's wait queue */ + union { + struct xpc_partition_sn2 sn2; + struct xpc_partition_uv uv; + } sn; + } ____cacheline_aligned; /* struct xpc_partition act_state values (for XPC HB) */ @@ -565,10 +587,10 @@ struct xpc_partition { #define XPC_P_DROPPED_IPI_WAIT_INTERVAL (0.25 * HZ) /* number of seconds to wait for other partitions to disengage */ -#define XPC_DISENGAGE_REQUEST_DEFAULT_TIMELIMIT 90 +#define XPC_DISENGAGE_DEFAULT_TIMELIMIT 90 -/* interval in seconds to print 'waiting disengagement' messages */ -#define XPC_DISENGAGE_PRINTMSG_INTERVAL 10 +/* interval in seconds to print 'waiting deactivation' messages */ +#define XPC_DEACTIVATE_PRINTMSG_INTERVAL 10 #define XPC_PARTID(_p) ((short)((_p) - &xpc_partitions[0])) @@ -578,13 +600,11 @@ extern struct xpc_registration xpc_registrations[]; /* found in xpc_main.c */ extern struct device *xpc_part; extern struct device *xpc_chan; -extern int xpc_disengage_request_timelimit; -extern int xpc_disengage_request_timedout; +extern int xpc_disengage_timelimit; +extern int xpc_disengage_timedout; extern atomic_t xpc_activate_IRQ_rcvd; extern wait_queue_head_t xpc_activate_IRQ_wq; extern void *xpc_heartbeating_to_mask; -extern irqreturn_t xpc_notify_IRQ_handler(int, void *); -extern void xpc_dropped_IPI_check(struct xpc_partition *); extern void xpc_activate_partition(struct xpc_partition *); extern void xpc_activate_kthreads(struct xpc_channel *, int); extern void xpc_create_kthreads(struct xpc_channel *, int, int); @@ -598,31 +618,34 @@ extern void (*xpc_online_heartbeat) (void); extern void (*xpc_check_remote_hb) (void); extern enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *); extern u64 (*xpc_get_IPI_flags) (struct xpc_partition *); +extern void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *); +extern void (*xpc_process_msg_IPI) (struct xpc_partition *, int); +extern int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *); extern struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *); -extern void (*xpc_initiate_partition_activation) (struct xpc_rsvd_page *, u64, - int); +extern void (*xpc_request_partition_activation) (struct xpc_rsvd_page *, u64, + int); +extern void (*xpc_request_partition_reactivation) (struct xpc_partition *); +extern void (*xpc_request_partition_deactivation) (struct xpc_partition *); +extern void (*xpc_cancel_partition_deactivation_request) ( + struct xpc_partition *); extern void (*xpc_process_activate_IRQ_rcvd) (int); extern enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *); extern void (*xpc_teardown_infrastructure) (struct xpc_partition *); -extern void (*xpc_mark_partition_engaged) (struct xpc_partition *); -extern void (*xpc_mark_partition_disengaged) (struct xpc_partition *); -extern void (*xpc_request_partition_disengage) (struct xpc_partition *); -extern void (*xpc_cancel_partition_disengage_request) (struct xpc_partition *); -extern u64 (*xpc_partition_engaged) (u64); -extern u64 (*xpc_partition_disengage_requested) (u64);; -extern void (*xpc_clear_partition_engaged) (u64); -extern void (*xpc_clear_partition_disengage_request) (u64); - -extern void (*xpc_IPI_send_local_activate) (int); -extern void (*xpc_IPI_send_activated) (struct xpc_partition *); -extern void (*xpc_IPI_send_local_reactivate) (int); -extern void (*xpc_IPI_send_disengage) (struct xpc_partition *); - -extern void (*xpc_IPI_send_closerequest) (struct xpc_channel *, - unsigned long *); -extern void (*xpc_IPI_send_closereply) (struct xpc_channel *, unsigned long *); -extern void (*xpc_IPI_send_openrequest) (struct xpc_channel *, unsigned long *); -extern void (*xpc_IPI_send_openreply) (struct xpc_channel *, unsigned long *); + +extern void (*xpc_indicate_partition_engaged) (struct xpc_partition *); +extern int (*xpc_partition_engaged) (short); +extern int (*xpc_any_partition_engaged) (void); +extern void (*xpc_indicate_partition_disengaged) (struct xpc_partition *); +extern void (*xpc_assume_partition_disengaged) (short); + +extern void (*xpc_send_channel_closerequest) (struct xpc_channel *, + unsigned long *); +extern void (*xpc_send_channel_closereply) (struct xpc_channel *, + unsigned long *); +extern void (*xpc_send_channel_openrequest) (struct xpc_channel *, + unsigned long *); +extern void (*xpc_send_channel_openreply) (struct xpc_channel *, + unsigned long *); extern enum xp_retval (*xpc_send_msg) (struct xpc_channel *, u32, void *, u16, u8, xpc_notify_func, void *); @@ -646,8 +669,6 @@ extern char *xpc_remote_copy_buffer; extern void *xpc_remote_copy_buffer_base; extern void *xpc_kmalloc_cacheline_aligned(size_t, gfp_t, void **); extern struct xpc_rsvd_page *xpc_setup_rsvd_page(void); -extern void xpc_allow_IPI_ops(void); -extern void xpc_restrict_IPI_ops(void); extern int xpc_identify_activate_IRQ_sender(void); extern int xpc_partition_disengaged(struct xpc_partition *); extern enum xp_retval xpc_mark_partition_active(struct xpc_partition *); diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index 55182c8dd32..48b16136305 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -201,7 +201,7 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) if (!(ch->flags & XPC_C_OPENREPLY)) { ch->flags |= XPC_C_OPENREPLY; - xpc_IPI_send_openreply(ch, irq_flags); + xpc_send_channel_openreply(ch, irq_flags); } if (!(ch->flags & XPC_C_ROPENREPLY)) @@ -219,52 +219,6 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) spin_lock_irqsave(&ch->lock, *irq_flags); } -/* - * Notify those who wanted to be notified upon delivery of their message. - */ -static void -xpc_notify_senders(struct xpc_channel *ch, enum xp_retval reason, s64 put) -{ - struct xpc_notify *notify; - u8 notify_type; - s64 get = ch->w_remote_GP.get - 1; - - while (++get < put && atomic_read(&ch->n_to_notify) > 0) { - - notify = &ch->notify_queue[get % ch->local_nentries]; - - /* - * See if the notify entry indicates it was associated with - * a message who's sender wants to be notified. It is possible - * that it is, but someone else is doing or has done the - * notification. - */ - notify_type = notify->type; - if (notify_type == 0 || - cmpxchg(¬ify->type, notify_type, 0) != notify_type) { - continue; - } - - DBUG_ON(notify_type != XPC_N_CALL); - - atomic_dec(&ch->n_to_notify); - - if (notify->func != NULL) { - dev_dbg(xpc_chan, "notify->func() called, notify=0x%p, " - "msg_number=%ld, partid=%d, channel=%d\n", - (void *)notify, get, ch->partid, ch->number); - - notify->func(reason, ch->partid, ch->number, - notify->key); - - dev_dbg(xpc_chan, "notify->func() returned, " - "notify=0x%p, msg_number=%ld, partid=%d, " - "channel=%d\n", (void *)notify, get, - ch->partid, ch->number); - } - } -} - /* * Free up message queues and other stuff that were allocated for the specified * channel. @@ -275,6 +229,8 @@ xpc_notify_senders(struct xpc_channel *ch, enum xp_retval reason, s64 put) static void xpc_free_msgqueues(struct xpc_channel *ch) { + struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; + DBUG_ON(!spin_is_locked(&ch->lock)); DBUG_ON(atomic_read(&ch->n_to_notify) != 0); @@ -287,15 +243,15 @@ xpc_free_msgqueues(struct xpc_channel *ch) ch->kthreads_assigned_limit = 0; ch->kthreads_idle_limit = 0; - ch->local_GP->get = 0; - ch->local_GP->put = 0; - ch->remote_GP.get = 0; - ch->remote_GP.put = 0; - ch->w_local_GP.get = 0; - ch->w_local_GP.put = 0; - ch->w_remote_GP.get = 0; - ch->w_remote_GP.put = 0; - ch->next_msg_to_pull = 0; + ch_sn2->local_GP->get = 0; + ch_sn2->local_GP->put = 0; + ch_sn2->remote_GP.get = 0; + ch_sn2->remote_GP.put = 0; + ch_sn2->w_local_GP.get = 0; + ch_sn2->w_local_GP.put = 0; + ch_sn2->w_remote_GP.get = 0; + ch_sn2->w_remote_GP.put = 0; + ch_sn2->next_msg_to_pull = 0; if (ch->flags & XPC_C_SETUP) { ch->flags &= ~XPC_C_SETUP; @@ -339,7 +295,7 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) if (part->act_state == XPC_P_DEACTIVATING) { /* can't proceed until the other side disengages from us */ - if (xpc_partition_engaged(1UL << ch->partid)) + if (xpc_partition_engaged(ch->partid)) return; } else { @@ -351,7 +307,7 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) if (!(ch->flags & XPC_C_CLOSEREPLY)) { ch->flags |= XPC_C_CLOSEREPLY; - xpc_IPI_send_closereply(ch, irq_flags); + xpc_send_channel_closereply(ch, irq_flags); } if (!(ch->flags & XPC_C_RCLOSEREPLY)) @@ -361,7 +317,7 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) /* wake those waiting for notify completion */ if (atomic_read(&ch->n_to_notify) > 0) { /* >>> we do callout while holding ch->lock */ - xpc_notify_senders(ch, ch->reason, ch->w_local_GP.put); + xpc_notify_senders_of_disconnect(ch); } /* both sides are disconnected now */ @@ -734,7 +690,7 @@ xpc_connect_channel(struct xpc_channel *ch) /* initiate the connection */ ch->flags |= (XPC_C_OPENREQUEST | XPC_C_CONNECTING); - xpc_IPI_send_openrequest(ch, &irq_flags); + xpc_send_channel_openrequest(ch, &irq_flags); xpc_process_connect(ch, &irq_flags); @@ -743,142 +699,6 @@ xpc_connect_channel(struct xpc_channel *ch) return xpSuccess; } -/* - * Clear some of the msg flags in the local message queue. - */ -static inline void -xpc_clear_local_msgqueue_flags(struct xpc_channel *ch) -{ - struct xpc_msg *msg; - s64 get; - - get = ch->w_remote_GP.get; - do { - msg = (struct xpc_msg *)((u64)ch->local_msgqueue + - (get % ch->local_nentries) * - ch->msg_size); - msg->flags = 0; - } while (++get < ch->remote_GP.get); -} - -/* - * Clear some of the msg flags in the remote message queue. - */ -static inline void -xpc_clear_remote_msgqueue_flags(struct xpc_channel *ch) -{ - struct xpc_msg *msg; - s64 put; - - put = ch->w_remote_GP.put; - do { - msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + - (put % ch->remote_nentries) * - ch->msg_size); - msg->flags = 0; - } while (++put < ch->remote_GP.put); -} - -static void -xpc_process_msg_IPI(struct xpc_partition *part, int ch_number) -{ - struct xpc_channel *ch = &part->channels[ch_number]; - int nmsgs_sent; - - ch->remote_GP = part->remote_GPs[ch_number]; - - /* See what, if anything, has changed for each connected channel */ - - xpc_msgqueue_ref(ch); - - if (ch->w_remote_GP.get == ch->remote_GP.get && - ch->w_remote_GP.put == ch->remote_GP.put) { - /* nothing changed since GPs were last pulled */ - xpc_msgqueue_deref(ch); - return; - } - - if (!(ch->flags & XPC_C_CONNECTED)) { - xpc_msgqueue_deref(ch); - return; - } - - /* - * First check to see if messages recently sent by us have been - * received by the other side. (The remote GET value will have - * changed since we last looked at it.) - */ - - if (ch->w_remote_GP.get != ch->remote_GP.get) { - - /* - * We need to notify any senders that want to be notified - * that their sent messages have been received by their - * intended recipients. We need to do this before updating - * w_remote_GP.get so that we don't allocate the same message - * queue entries prematurely (see xpc_allocate_msg()). - */ - if (atomic_read(&ch->n_to_notify) > 0) { - /* - * Notify senders that messages sent have been - * received and delivered by the other side. - */ - xpc_notify_senders(ch, xpMsgDelivered, - ch->remote_GP.get); - } - - /* - * Clear msg->flags in previously sent messages, so that - * they're ready for xpc_allocate_msg(). - */ - xpc_clear_local_msgqueue_flags(ch); - - ch->w_remote_GP.get = ch->remote_GP.get; - - dev_dbg(xpc_chan, "w_remote_GP.get changed to %ld, partid=%d, " - "channel=%d\n", ch->w_remote_GP.get, ch->partid, - ch->number); - - /* - * If anyone was waiting for message queue entries to become - * available, wake them up. - */ - if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) - wake_up(&ch->msg_allocate_wq); - } - - /* - * Now check for newly sent messages by the other side. (The remote - * PUT value will have changed since we last looked at it.) - */ - - if (ch->w_remote_GP.put != ch->remote_GP.put) { - /* - * Clear msg->flags in previously received messages, so that - * they're ready for xpc_get_deliverable_msg(). - */ - xpc_clear_remote_msgqueue_flags(ch); - - ch->w_remote_GP.put = ch->remote_GP.put; - - dev_dbg(xpc_chan, "w_remote_GP.put changed to %ld, partid=%d, " - "channel=%d\n", ch->w_remote_GP.put, ch->partid, - ch->number); - - nmsgs_sent = ch->w_remote_GP.put - ch->w_local_GP.get; - if (nmsgs_sent > 0) { - dev_dbg(xpc_chan, "msgs waiting to be copied and " - "delivered=%d, partid=%d, channel=%d\n", - nmsgs_sent, ch->partid, ch->number); - - if (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) - xpc_activate_kthreads(ch, nmsgs_sent); - } - } - - xpc_msgqueue_deref(ch); -} - void xpc_process_channel_activity(struct xpc_partition *part) { @@ -1117,7 +937,7 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch, XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY | XPC_C_CONNECTING | XPC_C_CONNECTED); - xpc_IPI_send_closerequest(ch, irq_flags); + xpc_send_channel_closerequest(ch, irq_flags); if (channel_was_connected) ch->flags |= XPC_C_WASCONNECTED; diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index 8780d5d00f6..563aaf4a2ff 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -26,7 +26,7 @@ * Caveats: * * . We currently have no way to determine which nasid an IPI came - * from. Thus, xpc_IPI_send() does a remote AMO write followed by + * from. Thus, >>> xpc_IPI_send() does a remote AMO write followed by * an IPI. The AMO indicates where data is to be pulled from, so * after the IPI arrives, the remote partition checks the AMO word. * The IPI can actually arrive before the AMO however, so other code @@ -89,9 +89,9 @@ static int xpc_hb_check_interval = XPC_HB_CHECK_DEFAULT_INTERVAL; static int xpc_hb_check_min_interval = 10; static int xpc_hb_check_max_interval = 120; -int xpc_disengage_request_timelimit = XPC_DISENGAGE_REQUEST_DEFAULT_TIMELIMIT; -static int xpc_disengage_request_min_timelimit; /* = 0 */ -static int xpc_disengage_request_max_timelimit = 120; +int xpc_disengage_timelimit = XPC_DISENGAGE_DEFAULT_TIMELIMIT; +static int xpc_disengage_min_timelimit; /* = 0 */ +static int xpc_disengage_max_timelimit = 120; static ctl_table xpc_sys_xpc_hb_dir[] = { { @@ -124,14 +124,14 @@ static ctl_table xpc_sys_xpc_dir[] = { .child = xpc_sys_xpc_hb_dir}, { .ctl_name = CTL_UNNUMBERED, - .procname = "disengage_request_timelimit", - .data = &xpc_disengage_request_timelimit, + .procname = "disengage_timelimit", + .data = &xpc_disengage_timelimit, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec_minmax, .strategy = &sysctl_intvec, - .extra1 = &xpc_disengage_request_min_timelimit, - .extra2 = &xpc_disengage_request_max_timelimit}, + .extra1 = &xpc_disengage_min_timelimit, + .extra2 = &xpc_disengage_max_timelimit}, {} }; static ctl_table xpc_sys_dir[] = { @@ -144,8 +144,8 @@ static ctl_table xpc_sys_dir[] = { }; static struct ctl_table_header *xpc_sysctl; -/* non-zero if any remote partition disengage request was timed out */ -int xpc_disengage_request_timedout; +/* non-zero if any remote partition disengage was timed out */ +int xpc_disengage_timedout; /* #of activate IRQs received */ atomic_t xpc_activate_IRQ_rcvd = ATOMIC_INIT(0); @@ -184,38 +184,36 @@ void (*xpc_online_heartbeat) (void); void (*xpc_check_remote_hb) (void); enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *part); +void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *ch); u64 (*xpc_get_IPI_flags) (struct xpc_partition *part); +void (*xpc_process_msg_IPI) (struct xpc_partition *part, int ch_number); +int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *ch); struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *ch); -void (*xpc_initiate_partition_activation) (struct xpc_rsvd_page *remote_rp, - u64 remote_rp_pa, int nasid); +void (*xpc_request_partition_activation) (struct xpc_rsvd_page *remote_rp, + u64 remote_rp_pa, int nasid); +void (*xpc_request_partition_reactivation) (struct xpc_partition *part); +void (*xpc_request_partition_deactivation) (struct xpc_partition *part); +void (*xpc_cancel_partition_deactivation_request) (struct xpc_partition *part); void (*xpc_process_activate_IRQ_rcvd) (int n_IRQs_expected); enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *part); void (*xpc_teardown_infrastructure) (struct xpc_partition *part); -void (*xpc_mark_partition_engaged) (struct xpc_partition *part); -void (*xpc_mark_partition_disengaged) (struct xpc_partition *part); -void (*xpc_request_partition_disengage) (struct xpc_partition *part); -void (*xpc_cancel_partition_disengage_request) (struct xpc_partition *part); -u64 (*xpc_partition_engaged) (u64 partid_mask); -u64 (*xpc_partition_disengage_requested) (u64 partid_mask); -void (*xpc_clear_partition_engaged) (u64 partid_mask); -void (*xpc_clear_partition_disengage_request) (u64 partid_mask); - -void (*xpc_IPI_send_local_activate) (int from_nasid); -void (*xpc_IPI_send_activated) (struct xpc_partition *part); -void (*xpc_IPI_send_local_reactivate) (int from_nasid); -void (*xpc_IPI_send_disengage) (struct xpc_partition *part); - -void (*xpc_IPI_send_closerequest) (struct xpc_channel *ch, - unsigned long *irq_flags); -void (*xpc_IPI_send_closereply) (struct xpc_channel *ch, - unsigned long *irq_flags); -void (*xpc_IPI_send_openrequest) (struct xpc_channel *ch, - unsigned long *irq_flags); -void (*xpc_IPI_send_openreply) (struct xpc_channel *ch, - unsigned long *irq_flags); +void (*xpc_indicate_partition_engaged) (struct xpc_partition *part); +int (*xpc_partition_engaged) (short partid); +int (*xpc_any_partition_engaged) (void); +void (*xpc_indicate_partition_disengaged) (struct xpc_partition *part); +void (*xpc_assume_partition_disengaged) (short partid); + +void (*xpc_send_channel_closerequest) (struct xpc_channel *ch, + unsigned long *irq_flags); +void (*xpc_send_channel_closereply) (struct xpc_channel *ch, + unsigned long *irq_flags); +void (*xpc_send_channel_openrequest) (struct xpc_channel *ch, + unsigned long *irq_flags); +void (*xpc_send_channel_openreply) (struct xpc_channel *ch, + unsigned long *irq_flags); enum xp_retval (*xpc_send_msg) (struct xpc_channel *ch, u32 flags, void *payload, u16 payload_size, u8 notify_type, @@ -223,19 +221,19 @@ enum xp_retval (*xpc_send_msg) (struct xpc_channel *ch, u32 flags, void (*xpc_received_msg) (struct xpc_channel *ch, struct xpc_msg *msg); /* - * Timer function to enforce the timelimit on the partition disengage request. + * Timer function to enforce the timelimit on the partition disengage. */ static void -xpc_timeout_partition_disengage_request(unsigned long data) +xpc_timeout_partition_disengage(unsigned long data) { struct xpc_partition *part = (struct xpc_partition *)data; - DBUG_ON(time_is_after_jiffies(part->disengage_request_timeout)); + DBUG_ON(time_is_after_jiffies(part->disengage_timeout)); (void)xpc_partition_disengaged(part); - DBUG_ON(part->disengage_request_timeout != 0); - DBUG_ON(xpc_partition_engaged(1UL << XPC_PARTID(part)) != 0); + DBUG_ON(part->disengage_timeout != 0); + DBUG_ON(xpc_partition_engaged(XPC_PARTID(part))); } /* @@ -464,7 +462,7 @@ xpc_activating(void *__partid) if (part->reason == xpReactivating) { /* interrupting ourselves results in activating partition */ - xpc_IPI_send_local_reactivate(part->reactivate_nasid); + xpc_request_partition_reactivation(part); } return 0; @@ -496,82 +494,6 @@ xpc_activate_partition(struct xpc_partition *part) } } -/* - * Check to see if there is any channel activity to/from the specified - * partition. - */ -static void -xpc_check_for_channel_activity(struct xpc_partition *part) -{ - u64 IPI_amo; - unsigned long irq_flags; - -/* this needs to be uncommented, but I'm thinking this function and the */ -/* ones that call it need to be moved into xpc_sn2.c... */ - IPI_amo = 0; /* = xpc_IPI_receive(part->local_IPI_amo_va); */ - if (IPI_amo == 0) - return; - - spin_lock_irqsave(&part->IPI_lock, irq_flags); - part->local_IPI_amo |= IPI_amo; - spin_unlock_irqrestore(&part->IPI_lock, irq_flags); - - dev_dbg(xpc_chan, "received IPI from partid=%d, IPI_amo=0x%lx\n", - XPC_PARTID(part), IPI_amo); - - xpc_wakeup_channel_mgr(part); -} - -/* - * Handle the receipt of a SGI_XPC_NOTIFY IRQ by seeing whether the specified - * partition actually sent it. Since SGI_XPC_NOTIFY IRQs may be shared by more - * than one partition, we use an AMO_t structure per partition to indicate - * whether a partition has sent an IPI or not. If it has, then wake up the - * associated kthread to handle it. - * - * All SGI_XPC_NOTIFY IRQs received by XPC are the result of IPIs sent by XPC - * running on other partitions. - * - * Noteworthy Arguments: - * - * irq - Interrupt ReQuest number. NOT USED. - * - * dev_id - partid of IPI's potential sender. - */ -irqreturn_t -xpc_notify_IRQ_handler(int irq, void *dev_id) -{ - short partid = (short)(u64)dev_id; - struct xpc_partition *part = &xpc_partitions[partid]; - - DBUG_ON(partid < 0 || partid >= xp_max_npartitions); - - if (xpc_part_ref(part)) { - xpc_check_for_channel_activity(part); - - xpc_part_deref(part); - } - return IRQ_HANDLED; -} - -/* - * Check to see if xpc_notify_IRQ_handler() dropped any IPIs on the floor - * because the write to their associated IPI amo completed after the IRQ/IPI - * was received. - */ -void -xpc_dropped_IPI_check(struct xpc_partition *part) -{ - if (xpc_part_ref(part)) { - xpc_check_for_channel_activity(part); - - part->dropped_IPI_timer.expires = jiffies + - XPC_P_DROPPED_IPI_WAIT_INTERVAL; - add_timer(&part->dropped_IPI_timer); - xpc_part_deref(part); - } -} - void xpc_activate_kthreads(struct xpc_channel *ch, int needed) { @@ -616,7 +538,7 @@ xpc_kthread_waitmsgs(struct xpc_partition *part, struct xpc_channel *ch) do { /* deliver messages to their intended recipients */ - while (ch->w_local_GP.get < ch->w_remote_GP.put && + while (xpc_n_of_deliverable_msgs(ch) > 0 && !(ch->flags & XPC_C_DISCONNECTING)) { xpc_deliver_msg(ch); } @@ -632,7 +554,7 @@ xpc_kthread_waitmsgs(struct xpc_partition *part, struct xpc_channel *ch) "wait_event_interruptible_exclusive()\n"); (void)wait_event_interruptible_exclusive(ch->idle_wq, - (ch->w_local_GP.get < ch->w_remote_GP.put || + (xpc_n_of_deliverable_msgs(ch) > 0 || (ch->flags & XPC_C_DISCONNECTING))); atomic_dec(&ch->kthreads_idle); @@ -677,7 +599,7 @@ xpc_kthread_start(void *args) * additional kthreads to help deliver them. We only * need one less than total #of messages to deliver. */ - n_needed = ch->w_remote_GP.put - ch->w_local_GP.get - 1; + n_needed = xpc_n_of_deliverable_msgs(ch) - 1; if (n_needed > 0 && !(ch->flags & XPC_C_DISCONNECTING)) xpc_activate_kthreads(ch, n_needed); @@ -703,11 +625,9 @@ xpc_kthread_start(void *args) } spin_unlock_irqrestore(&ch->lock, irq_flags); - if (atomic_dec_return(&ch->kthreads_assigned) == 0) { - if (atomic_dec_return(&part->nchannels_engaged) == 0) { - xpc_mark_partition_disengaged(part); - xpc_IPI_send_disengage(part); - } + if (atomic_dec_return(&ch->kthreads_assigned) == 0 && + atomic_dec_return(&part->nchannels_engaged) == 0) { + xpc_indicate_partition_disengaged(part); } xpc_msgqueue_deref(ch); @@ -758,9 +678,9 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed, } else if (ch->flags & XPC_C_DISCONNECTING) { break; - } else if (atomic_inc_return(&ch->kthreads_assigned) == 1) { - if (atomic_inc_return(&part->nchannels_engaged) == 1) - xpc_mark_partition_engaged(part); + } else if (atomic_inc_return(&ch->kthreads_assigned) == 1 && + atomic_inc_return(&part->nchannels_engaged) == 1) { + xpc_indicate_partition_engaged(part); } (void)xpc_part_ref(part); xpc_msgqueue_ref(ch); @@ -782,8 +702,7 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed, if (atomic_dec_return(&ch->kthreads_assigned) == 0 && atomic_dec_return(&part->nchannels_engaged) == 0) { - xpc_mark_partition_disengaged(part); - xpc_IPI_send_disengage(part); + xpc_indicate_partition_disengaged(part); } xpc_msgqueue_deref(ch); xpc_part_deref(part); @@ -862,7 +781,7 @@ xpc_do_exit(enum xp_retval reason) short partid; int active_part_count, printed_waiting_msg = 0; struct xpc_partition *part; - unsigned long printmsg_time, disengage_request_timeout = 0; + unsigned long printmsg_time, disengage_timeout = 0; /* a 'rmmod XPC' and a 'reboot' cannot both end up here together */ DBUG_ON(xpc_exiting == 1); @@ -886,8 +805,8 @@ xpc_do_exit(enum xp_retval reason) /* wait for all partitions to become inactive */ - printmsg_time = jiffies + (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ); - xpc_disengage_request_timedout = 0; + printmsg_time = jiffies + (XPC_DEACTIVATE_PRINTMSG_INTERVAL * HZ); + xpc_disengage_timedout = 0; do { active_part_count = 0; @@ -904,36 +823,32 @@ xpc_do_exit(enum xp_retval reason) XPC_DEACTIVATE_PARTITION(part, reason); - if (part->disengage_request_timeout > - disengage_request_timeout) { - disengage_request_timeout = - part->disengage_request_timeout; - } + if (part->disengage_timeout > disengage_timeout) + disengage_timeout = part->disengage_timeout; } - if (xpc_partition_engaged(-1UL)) { + if (xpc_any_partition_engaged()) { if (time_is_before_jiffies(printmsg_time)) { dev_info(xpc_part, "waiting for remote " - "partitions to disengage, timeout in " - "%ld seconds\n", - (disengage_request_timeout - jiffies) - / HZ); + "partitions to deactivate, timeout in " + "%ld seconds\n", (disengage_timeout - + jiffies) / HZ); printmsg_time = jiffies + - (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ); + (XPC_DEACTIVATE_PRINTMSG_INTERVAL * HZ); printed_waiting_msg = 1; } } else if (active_part_count > 0) { if (printed_waiting_msg) { dev_info(xpc_part, "waiting for local partition" - " to disengage\n"); + " to deactivate\n"); printed_waiting_msg = 0; } } else { - if (!xpc_disengage_request_timedout) { + if (!xpc_disengage_timedout) { dev_info(xpc_part, "all partitions have " - "disengaged\n"); + "deactivated\n"); } break; } @@ -943,7 +858,7 @@ xpc_do_exit(enum xp_retval reason) } while (1); - DBUG_ON(xpc_partition_engaged(-1UL)); + DBUG_ON(xpc_any_partition_engaged()); DBUG_ON(xpc_any_hbs_allowed() != 0); /* indicate to others that our reserved page is uninitialized */ @@ -996,15 +911,16 @@ xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused) } /* - * Notify other partitions to disengage from all references to our memory. + * Notify other partitions to deactivate from us by first disengaging from all + * references to our memory. */ static void -xpc_die_disengage(void) +xpc_die_deactivate(void) { struct xpc_partition *part; short partid; - unsigned long engaged; - long time, printmsg_time, disengage_request_timeout; + int any_engaged; + long time, printmsg_time, disengage_timeout; /* keep xpc_hb_checker thread from doing anything (just in case) */ xpc_exiting = 1; @@ -1014,43 +930,37 @@ xpc_die_disengage(void) for (partid = 0; partid < xp_max_npartitions; partid++) { part = &xpc_partitions[partid]; - if (!XPC_SUPPORTS_DISENGAGE_REQUEST(part-> - remote_vars_version)) { - - /* just in case it was left set by an earlier XPC */ - xpc_clear_partition_engaged(1UL << partid); - continue; - } - - if (xpc_partition_engaged(1UL << partid) || + if (xpc_partition_engaged(partid) || part->act_state != XPC_P_INACTIVE) { - xpc_request_partition_disengage(part); - xpc_mark_partition_disengaged(part); - xpc_IPI_send_disengage(part); + xpc_request_partition_deactivation(part); + xpc_indicate_partition_disengaged(part); } } time = rtc_time(); printmsg_time = time + - (XPC_DISENGAGE_PRINTMSG_INTERVAL * sn_rtc_cycles_per_second); - disengage_request_timeout = time + - (xpc_disengage_request_timelimit * sn_rtc_cycles_per_second); + (XPC_DEACTIVATE_PRINTMSG_INTERVAL * sn_rtc_cycles_per_second); + disengage_timeout = time + + (xpc_disengage_timelimit * sn_rtc_cycles_per_second); - /* wait for all other partitions to disengage from us */ + /* + * Though we requested that all other partitions deactivate from us, + * we only wait until they've all disengaged. + */ while (1) { - engaged = xpc_partition_engaged(-1UL); - if (!engaged) { - dev_info(xpc_part, "all partitions have disengaged\n"); + any_engaged = xpc_any_partition_engaged(); + if (!any_engaged) { + dev_info(xpc_part, "all partitions have deactivated\n"); break; } time = rtc_time(); - if (time >= disengage_request_timeout) { + if (time >= disengage_timeout) { for (partid = 0; partid < xp_max_npartitions; partid++) { - if (engaged & (1UL << partid)) { - dev_info(xpc_part, "disengage from " + if (xpc_partition_engaged(partid)) { + dev_info(xpc_part, "deactivate from " "remote partition %d timed " "out\n", partid); } @@ -1060,11 +970,11 @@ xpc_die_disengage(void) if (time >= printmsg_time) { dev_info(xpc_part, "waiting for remote partitions to " - "disengage, timeout in %ld seconds\n", - (disengage_request_timeout - time) / + "deactivate, timeout in %ld seconds\n", + (disengage_timeout - time) / sn_rtc_cycles_per_second); printmsg_time = time + - (XPC_DISENGAGE_PRINTMSG_INTERVAL * + (XPC_DEACTIVATE_PRINTMSG_INTERVAL * sn_rtc_cycles_per_second); } } @@ -1084,7 +994,7 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) switch (event) { case DIE_MACHINE_RESTART: case DIE_MACHINE_HALT: - xpc_die_disengage(); + xpc_die_deactivate(); break; case DIE_KDEBUG_ENTER: @@ -1183,10 +1093,10 @@ xpc_init(void) part->act_state = XPC_P_INACTIVE; XPC_SET_REASON(part, 0, 0); - init_timer(&part->disengage_request_timer); - part->disengage_request_timer.function = - xpc_timeout_partition_disengage_request; - part->disengage_request_timer.data = (unsigned long)part; + init_timer(&part->disengage_timer); + part->disengage_timer.function = + xpc_timeout_partition_disengage; + part->disengage_timer.data = (unsigned long)part; part->setup_state = XPC_P_UNSET; init_waitqueue_head(&part->teardown_wq); @@ -1295,9 +1205,9 @@ module_param(xpc_hb_check_interval, int, 0); MODULE_PARM_DESC(xpc_hb_check_interval, "Number of seconds between " "heartbeat checks."); -module_param(xpc_disengage_request_timelimit, int, 0); -MODULE_PARM_DESC(xpc_disengage_request_timelimit, "Number of seconds to wait " - "for disengage request to complete."); +module_param(xpc_disengage_timelimit, int, 0); +MODULE_PARM_DESC(xpc_disengage_timelimit, "Number of seconds to wait " + "for disengage to complete."); module_param(xpc_kdebug_ignore, int, 0); MODULE_PARM_DESC(xpc_kdebug_ignore, "Should lack of heartbeat be ignored by " diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index bf9b1193bd2..c769ab8f74e 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -242,7 +242,7 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, return xpBadVersion; } - /* check that both local and remote partids are valid for each side */ + /* check that both remote and local partids are valid for each side */ if (remote_rp->SAL_partid < 0 || remote_rp->SAL_partid >= xp_max_npartitions || remote_rp->max_npartitions <= sn_partition_id) { @@ -256,8 +256,9 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, } /* - * See if the other side has responded to a partition disengage request - * from us. + * See if the other side has responded to a partition deactivate request + * from us. Though we requested the remote partition to deactivate with regard + * to us, we really only need to wait for the other side to disengage from us. */ int xpc_partition_disengaged(struct xpc_partition *part) @@ -265,41 +266,37 @@ xpc_partition_disengaged(struct xpc_partition *part) short partid = XPC_PARTID(part); int disengaged; - disengaged = (xpc_partition_engaged(1UL << partid) == 0); - if (part->disengage_request_timeout) { + disengaged = !xpc_partition_engaged(partid); + if (part->disengage_timeout) { if (!disengaged) { - if (time_is_after_jiffies(part-> - disengage_request_timeout)) { + if (time_is_after_jiffies(part->disengage_timeout)) { /* timelimit hasn't been reached yet */ return 0; } /* - * Other side hasn't responded to our disengage + * Other side hasn't responded to our deactivate * request in a timely fashion, so assume it's dead. */ - dev_info(xpc_part, "disengage from remote partition %d " - "timed out\n", partid); - xpc_disengage_request_timedout = 1; - xpc_clear_partition_engaged(1UL << partid); + dev_info(xpc_part, "deactivate request to remote " + "partition %d timed out\n", partid); + xpc_disengage_timedout = 1; + xpc_assume_partition_disengaged(partid); disengaged = 1; } - part->disengage_request_timeout = 0; + part->disengage_timeout = 0; /* cancel the timer function, provided it's not us */ - if (!in_interrupt()) { - del_singleshot_timer_sync(&part-> - disengage_request_timer); - } + if (!in_interrupt()) + del_singleshot_timer_sync(&part->disengage_timer); DBUG_ON(part->act_state != XPC_P_DEACTIVATING && part->act_state != XPC_P_INACTIVE); if (part->act_state != XPC_P_INACTIVE) xpc_wakeup_channel_mgr(part); - if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) - xpc_cancel_partition_disengage_request(part); + xpc_cancel_partition_deactivation_request(part); } return disengaged; } @@ -329,7 +326,7 @@ xpc_mark_partition_active(struct xpc_partition *part) } /* - * Notify XPC that the partition is down. + * Start the process of deactivating the specified partition. */ void xpc_deactivate_partition(const int line, struct xpc_partition *part, @@ -344,7 +341,7 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part, spin_unlock_irqrestore(&part->act_lock, irq_flags); if (reason == xpReactivating) { /* we interrupt ourselves to reactivate partition */ - xpc_IPI_send_local_reactivate(part->reactivate_nasid); + xpc_request_partition_reactivation(part); } return; } @@ -362,17 +359,13 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part, spin_unlock_irqrestore(&part->act_lock, irq_flags); - if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) { - xpc_request_partition_disengage(part); - xpc_IPI_send_disengage(part); + /* ask remote partition to deactivate with regard to us */ + xpc_request_partition_deactivation(part); - /* set a timelimit on the disengage request */ - part->disengage_request_timeout = jiffies + - (xpc_disengage_request_timelimit * HZ); - part->disengage_request_timer.expires = - part->disengage_request_timeout; - add_timer(&part->disengage_request_timer); - } + /* set a timelimit on the disengage phase of the deactivation request */ + part->disengage_timeout = jiffies + (xpc_disengage_timelimit * HZ); + part->disengage_timer.expires = part->disengage_timeout; + add_timer(&part->disengage_timer); dev_dbg(xpc_part, "bringing partition %d down, reason = %d\n", XPC_PARTID(part), reason); @@ -505,8 +498,8 @@ xpc_discovery(void) continue; } - xpc_initiate_partition_activation(remote_rp, - remote_rp_pa, nasid); + xpc_request_partition_activation(remote_rp, + remote_rp_pa, nasid); } } diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index 4659f6cb885..69d74bd5689 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -196,37 +196,85 @@ xpc_activate_IRQ_send_local_sn2(int from_nasid) wake_up_interruptible(&xpc_activate_IRQ_wq); } -static void -xpc_IPI_send_local_activate_sn2(int from_nasid) -{ - xpc_activate_IRQ_send_local_sn2(from_nasid); -} +/* + * IPIs associated with SGI_XPC_NOTIFY IRQ. + */ +/* + * Check to see if there is any channel activity to/from the specified + * partition. + */ static void -xpc_IPI_send_activated_sn2(struct xpc_partition *part) +xpc_check_for_channel_activity_sn2(struct xpc_partition *part) { - xpc_activate_IRQ_send_sn2(part->remote_amos_page_pa, - cnodeid_to_nasid(0), part->remote_act_nasid, - part->remote_act_phys_cpuid); -} + u64 IPI_amo; + unsigned long irq_flags; -static void -xpc_IPI_send_local_reactivate_sn2(int from_nasid) -{ - xpc_activate_IRQ_send_local_sn2(from_nasid); + IPI_amo = xpc_IPI_receive_sn2(part->sn.sn2.local_IPI_amo_va); + if (IPI_amo == 0) + return; + + spin_lock_irqsave(&part->IPI_lock, irq_flags); + part->local_IPI_amo |= IPI_amo; + spin_unlock_irqrestore(&part->IPI_lock, irq_flags); + + dev_dbg(xpc_chan, "received IPI from partid=%d, IPI_amo=0x%lx\n", + XPC_PARTID(part), IPI_amo); + + xpc_wakeup_channel_mgr(part); } -static void -xpc_IPI_send_disengage_sn2(struct xpc_partition *part) +/* + * Handle the receipt of a SGI_XPC_NOTIFY IRQ by seeing whether the specified + * partition actually sent it. Since SGI_XPC_NOTIFY IRQs may be shared by more + * than one partition, we use an AMO_t structure per partition to indicate + * whether a partition has sent an IPI or not. If it has, then wake up the + * associated kthread to handle it. + * + * All SGI_XPC_NOTIFY IRQs received by XPC are the result of IPIs sent by XPC + * running on other partitions. + * + * Noteworthy Arguments: + * + * irq - Interrupt ReQuest number. NOT USED. + * + * dev_id - partid of IPI's potential sender. + */ +static irqreturn_t +xpc_handle_notify_IRQ_sn2(int irq, void *dev_id) { - xpc_activate_IRQ_send_sn2(part->remote_amos_page_pa, - cnodeid_to_nasid(0), part->remote_act_nasid, - part->remote_act_phys_cpuid); + short partid = (short)(u64)dev_id; + struct xpc_partition *part = &xpc_partitions[partid]; + + DBUG_ON(partid < 0 || partid >= xp_max_npartitions); + + if (xpc_part_ref(part)) { + xpc_check_for_channel_activity_sn2(part); + + xpc_part_deref(part); + } + return IRQ_HANDLED; } /* - * IPIs associated with SGI_XPC_NOTIFY IRQ. + * Check to see if xpc_handle_notify_IRQ_sn2() dropped any IPIs on the floor + * because the write to their associated IPI amo completed after the IRQ/IPI + * was received. */ +static void +xpc_dropped_notify_IRQ_check_sn2(struct xpc_partition *part) +{ + struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; + + if (xpc_part_ref(part)) { + xpc_check_for_channel_activity_sn2(part); + + part_sn2->dropped_notify_IRQ_timer.expires = jiffies + + XPC_P_DROPPED_IPI_WAIT_INTERVAL; + add_timer(&part_sn2->dropped_notify_IRQ_timer); + xpc_part_deref(part); + } +} /* * Send an IPI to the remote partition that is associated with the @@ -237,13 +285,14 @@ xpc_notify_IRQ_send_sn2(struct xpc_channel *ch, u8 ipi_flag, char *ipi_flag_string, unsigned long *irq_flags) { struct xpc_partition *part = &xpc_partitions[ch->partid]; + struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; enum xp_retval ret; if (likely(part->act_state != XPC_P_DEACTIVATING)) { - ret = xpc_IPI_send_sn2(part->remote_IPI_amo_va, + ret = xpc_IPI_send_sn2(part_sn2->remote_IPI_amo_va, (u64)ipi_flag << (ch->number * 8), - part->remote_IPI_nasid, - part->remote_IPI_phys_cpuid, + part_sn2->remote_IPI_nasid, + part_sn2->remote_IPI_phys_cpuid, SGI_XPC_NOTIFY); dev_dbg(xpc_chan, "%s sent to partid=%d, channel=%d, ret=%d\n", ipi_flag_string, ch->partid, ch->number, ret); @@ -263,7 +312,7 @@ xpc_notify_IRQ_send_sn2(struct xpc_channel *ch, u8 ipi_flag, /* * Make it look like the remote partition, which is associated with the * specified channel, sent us an IPI. This faked IPI will be handled - * by xpc_dropped_IPI_check(). + * by xpc_dropped_notify_IRQ_check_sn2(). */ static void xpc_notify_IRQ_send_local_sn2(struct xpc_channel *ch, u8 ipi_flag, @@ -271,7 +320,7 @@ xpc_notify_IRQ_send_local_sn2(struct xpc_channel *ch, u8 ipi_flag, { struct xpc_partition *part = &xpc_partitions[ch->partid]; - FETCHOP_STORE_OP(TO_AMO((u64)&part->local_IPI_amo_va->variable), + FETCHOP_STORE_OP(TO_AMO((u64)&part->sn.sn2.local_IPI_amo_va->variable), FETCHOP_OR, ((u64)ipi_flag << (ch->number * 8))); dev_dbg(xpc_chan, "%s sent local from partid=%d, channel=%d\n", ipi_flag_string, ch->partid, ch->number); @@ -281,7 +330,8 @@ xpc_notify_IRQ_send_local_sn2(struct xpc_channel *ch, u8 ipi_flag, xpc_notify_IRQ_send_local_sn2(_ch, _ipi_f, #_ipi_f) static void -xpc_IPI_send_closerequest_sn2(struct xpc_channel *ch, unsigned long *irq_flags) +xpc_send_channel_closerequest_sn2(struct xpc_channel *ch, + unsigned long *irq_flags) { struct xpc_openclose_args *args = ch->local_openclose_args; @@ -290,13 +340,15 @@ xpc_IPI_send_closerequest_sn2(struct xpc_channel *ch, unsigned long *irq_flags) } static void -xpc_IPI_send_closereply_sn2(struct xpc_channel *ch, unsigned long *irq_flags) +xpc_send_channel_closereply_sn2(struct xpc_channel *ch, + unsigned long *irq_flags) { XPC_NOTIFY_IRQ_SEND_SN2(ch, XPC_IPI_CLOSEREPLY, irq_flags); } static void -xpc_IPI_send_openrequest_sn2(struct xpc_channel *ch, unsigned long *irq_flags) +xpc_send_channel_openrequest_sn2(struct xpc_channel *ch, + unsigned long *irq_flags) { struct xpc_openclose_args *args = ch->local_openclose_args; @@ -306,7 +358,7 @@ xpc_IPI_send_openrequest_sn2(struct xpc_channel *ch, unsigned long *irq_flags) } static void -xpc_IPI_send_openreply_sn2(struct xpc_channel *ch, unsigned long *irq_flags) +xpc_send_channel_openreply_sn2(struct xpc_channel *ch, unsigned long *irq_flags) { struct xpc_openclose_args *args = ch->local_openclose_args; @@ -317,13 +369,13 @@ xpc_IPI_send_openreply_sn2(struct xpc_channel *ch, unsigned long *irq_flags) } static void -xpc_IPI_send_msgrequest_sn2(struct xpc_channel *ch) +xpc_send_channel_msgrequest_sn2(struct xpc_channel *ch) { XPC_NOTIFY_IRQ_SEND_SN2(ch, XPC_IPI_MSGREQUEST, NULL); } static void -xpc_IPI_send_local_msgrequest_sn2(struct xpc_channel *ch) +xpc_send_channel_local_msgrequest_sn2(struct xpc_channel *ch) { XPC_NOTIFY_IRQ_SEND_LOCAL_SN2(ch, XPC_IPI_MSGREQUEST); } @@ -334,10 +386,10 @@ xpc_IPI_send_local_msgrequest_sn2(struct xpc_channel *ch) */ static void -xpc_mark_partition_engaged_sn2(struct xpc_partition *part) +xpc_indicate_partition_engaged_sn2(struct xpc_partition *part) { unsigned long irq_flags; - AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + + AMO_t *amo = (AMO_t *)__va(part->sn.sn2.remote_amos_page_pa + (XPC_ENGAGED_PARTITIONS_AMO * sizeof(AMO_t))); @@ -360,10 +412,11 @@ xpc_mark_partition_engaged_sn2(struct xpc_partition *part) } static void -xpc_mark_partition_disengaged_sn2(struct xpc_partition *part) +xpc_indicate_partition_disengaged_sn2(struct xpc_partition *part) { + struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; unsigned long irq_flags; - AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + + AMO_t *amo = (AMO_t *)__va(part_sn2->remote_amos_page_pa + (XPC_ENGAGED_PARTITIONS_AMO * sizeof(AMO_t))); @@ -383,96 +436,44 @@ xpc_mark_partition_disengaged_sn2(struct xpc_partition *part) xp_nofault_PIOR_target)); local_irq_restore(irq_flags); -} - -static void -xpc_request_partition_disengage_sn2(struct xpc_partition *part) -{ - unsigned long irq_flags; - AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + - (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t))); - - local_irq_save(irq_flags); - /* set bit corresponding to our partid in remote partition's AMO */ - FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, - (1UL << sn_partition_id)); /* - * We must always use the nofault function regardless of whether we - * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we - * didn't, we'd never know that the other partition is down and would - * keep sending IPIs and AMOs to it until the heartbeat times out. + * Send activate IRQ to get other side to see that we've cleared our + * bit in their engaged partitions AMO. */ - (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> - variable), - xp_nofault_PIOR_target)); - - local_irq_restore(irq_flags); + xpc_activate_IRQ_send_sn2(part_sn2->remote_amos_page_pa, + cnodeid_to_nasid(0), + part_sn2->activate_IRQ_nasid, + part_sn2->activate_IRQ_phys_cpuid); } -static void -xpc_cancel_partition_disengage_request_sn2(struct xpc_partition *part) -{ - unsigned long irq_flags; - AMO_t *amo = (AMO_t *)__va(part->remote_amos_page_pa + - (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t))); - - local_irq_save(irq_flags); - - /* clear bit corresponding to our partid in remote partition's AMO */ - FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, - ~(1UL << sn_partition_id)); - /* - * We must always use the nofault function regardless of whether we - * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we - * didn't, we'd never know that the other partition is down and would - * keep sending IPIs and AMOs to it until the heartbeat times out. - */ - (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> - variable), - xp_nofault_PIOR_target)); - - local_irq_restore(irq_flags); -} - -static u64 -xpc_partition_engaged_sn2(u64 partid_mask) +static int +xpc_partition_engaged_sn2(short partid) { AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; - /* return our partition's AMO variable ANDed with partid_mask */ + /* our partition's AMO variable ANDed with partid mask */ return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & - partid_mask); + (1UL << partid)) != 0; } -static u64 -xpc_partition_disengage_requested_sn2(u64 partid_mask) -{ - AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO; - - /* return our partition's AMO variable ANDed with partid_mask */ - return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & - partid_mask); -} - -static void -xpc_clear_partition_engaged_sn2(u64 partid_mask) +static int +xpc_any_partition_engaged_sn2(void) { AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; - /* clear bit(s) based on partid_mask in our partition's AMO */ - FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, - ~partid_mask); + /* our partition's AMO variable */ + return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) != 0; } static void -xpc_clear_partition_disengage_request_sn2(u64 partid_mask) +xpc_assume_partition_disengaged_sn2(short partid) { - AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO; + AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; - /* clear bit(s) based on partid_mask in our partition's AMO */ + /* clear bit(s) based on partid mask in our partition's AMO */ FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, - ~partid_mask); + ~(1UL << partid)); } /* original protection values for each node */ @@ -545,7 +546,6 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) xpc_vars_part = (struct xpc_vars_part_sn2 *)((u8 *)XPC_RP_VARS(rp) + XPC_RP_VARS_SIZE); - /* * Before clearing xpc_vars, see if a page of AMOs had been previously * allocated. If not we'll need to allocate one and set permissions @@ -583,8 +583,8 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) memset(xpc_vars, 0, sizeof(struct xpc_vars_sn2)); xpc_vars->version = XPC_V_VERSION; - xpc_vars->act_nasid = cpuid_to_nasid(0); - xpc_vars->act_phys_cpuid = cpu_physical_id(0); + xpc_vars->activate_IRQ_nasid = cpuid_to_nasid(0); + xpc_vars->activate_IRQ_phys_cpuid = cpu_physical_id(0); xpc_vars->vars_part_pa = __pa(xpc_vars_part); xpc_vars->amos_page_pa = ia64_tpa((u64)amos_page); xpc_vars->amos_page = amos_page; /* save for next load of XPC */ @@ -599,7 +599,7 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) /* initialize the engaged remote partitions related AMO variables */ (void)xpc_IPI_init_sn2(XPC_ENGAGED_PARTITIONS_AMO); - (void)xpc_IPI_init_sn2(XPC_DISENGAGE_REQUEST_AMO); + (void)xpc_IPI_init_sn2(XPC_DEACTIVATE_REQUEST_AMO); return xpSuccess; } @@ -671,7 +671,7 @@ xpc_check_remote_hb_sn2(void) /* pull the remote_hb cache line */ ret = xp_remote_memcpy(remote_vars, - (void *)part->remote_vars_pa, + (void *)part->sn.sn2.remote_vars_pa, XPC_RP_VARS_SIZE); if (ret != xpSuccess) { XPC_DEACTIVATE_PARTITION(part, ret); @@ -726,10 +726,86 @@ xpc_get_remote_vars_sn2(u64 remote_vars_pa, struct xpc_vars_sn2 *remote_vars) } static void -xpc_initiate_partition_activation_sn2(struct xpc_rsvd_page *remote_rp, - u64 remote_rp_pa, int nasid) +xpc_request_partition_activation_sn2(struct xpc_rsvd_page *remote_rp, + u64 remote_rp_pa, int nasid) { - xpc_IPI_send_local_activate(nasid); + xpc_activate_IRQ_send_local_sn2(nasid); +} + +static void +xpc_request_partition_reactivation_sn2(struct xpc_partition *part) +{ + xpc_activate_IRQ_send_local_sn2(part->sn.sn2.activate_IRQ_nasid); +} + +static void +xpc_request_partition_deactivation_sn2(struct xpc_partition *part) +{ + struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; + unsigned long irq_flags; + AMO_t *amo = (AMO_t *)__va(part_sn2->remote_amos_page_pa + + (XPC_DEACTIVATE_REQUEST_AMO * sizeof(AMO_t))); + + local_irq_save(irq_flags); + + /* set bit corresponding to our partid in remote partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, + (1UL << sn_partition_id)); + /* + * We must always use the nofault function regardless of whether we + * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we + * didn't, we'd never know that the other partition is down and would + * keep sending IPIs and AMOs to it until the heartbeat times out. + */ + (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), + xp_nofault_PIOR_target)); + + local_irq_restore(irq_flags); + + /* + * Send activate IRQ to get other side to see that we've set our + * bit in their deactivate request AMO. + */ + xpc_activate_IRQ_send_sn2(part_sn2->remote_amos_page_pa, + cnodeid_to_nasid(0), + part_sn2->activate_IRQ_nasid, + part_sn2->activate_IRQ_phys_cpuid); +} + +static void +xpc_cancel_partition_deactivation_request_sn2(struct xpc_partition *part) +{ + unsigned long irq_flags; + AMO_t *amo = (AMO_t *)__va(part->sn.sn2.remote_amos_page_pa + + (XPC_DEACTIVATE_REQUEST_AMO * sizeof(AMO_t))); + + local_irq_save(irq_flags); + + /* clear bit corresponding to our partid in remote partition's AMO */ + FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, + ~(1UL << sn_partition_id)); + /* + * We must always use the nofault function regardless of whether we + * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we + * didn't, we'd never know that the other partition is down and would + * keep sending IPIs and AMOs to it until the heartbeat times out. + */ + (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> + variable), + xp_nofault_PIOR_target)); + + local_irq_restore(irq_flags); +} + +static int +xpc_partition_deactivation_requested_sn2(short partid) +{ + AMO_t *amo = xpc_vars->amos_page + XPC_DEACTIVATE_REQUEST_AMO; + + /* our partition's AMO variable ANDed with partid mask */ + return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & + (1UL << partid)) != 0; } /* @@ -741,6 +817,8 @@ xpc_update_partition_info_sn2(struct xpc_partition *part, u8 remote_rp_version, u64 remote_vars_pa, struct xpc_vars_sn2 *remote_vars) { + struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; + part->remote_rp_version = remote_rp_version; dev_dbg(xpc_part, " remote_rp_version = 0x%016x\n", part->remote_rp_version); @@ -752,33 +830,34 @@ xpc_update_partition_info_sn2(struct xpc_partition *part, u8 remote_rp_version, part->remote_rp_pa = remote_rp_pa; dev_dbg(xpc_part, " remote_rp_pa = 0x%016lx\n", part->remote_rp_pa); - part->remote_vars_pa = remote_vars_pa; + part_sn2->remote_vars_pa = remote_vars_pa; dev_dbg(xpc_part, " remote_vars_pa = 0x%016lx\n", - part->remote_vars_pa); + part_sn2->remote_vars_pa); part->last_heartbeat = remote_vars->heartbeat; dev_dbg(xpc_part, " last_heartbeat = 0x%016lx\n", part->last_heartbeat); - part->remote_vars_part_pa = remote_vars->vars_part_pa; + part_sn2->remote_vars_part_pa = remote_vars->vars_part_pa; dev_dbg(xpc_part, " remote_vars_part_pa = 0x%016lx\n", - part->remote_vars_part_pa); + part_sn2->remote_vars_part_pa); - part->remote_act_nasid = remote_vars->act_nasid; - dev_dbg(xpc_part, " remote_act_nasid = 0x%x\n", - part->remote_act_nasid); + part_sn2->activate_IRQ_nasid = remote_vars->activate_IRQ_nasid; + dev_dbg(xpc_part, " activate_IRQ_nasid = 0x%x\n", + part_sn2->activate_IRQ_nasid); - part->remote_act_phys_cpuid = remote_vars->act_phys_cpuid; - dev_dbg(xpc_part, " remote_act_phys_cpuid = 0x%x\n", - part->remote_act_phys_cpuid); + part_sn2->activate_IRQ_phys_cpuid = + remote_vars->activate_IRQ_phys_cpuid; + dev_dbg(xpc_part, " activate_IRQ_phys_cpuid = 0x%x\n", + part_sn2->activate_IRQ_phys_cpuid); - part->remote_amos_page_pa = remote_vars->amos_page_pa; + part_sn2->remote_amos_page_pa = remote_vars->amos_page_pa; dev_dbg(xpc_part, " remote_amos_page_pa = 0x%lx\n", - part->remote_amos_page_pa); + part_sn2->remote_amos_page_pa); - part->remote_vars_version = remote_vars->version; + part_sn2->remote_vars_version = remote_vars->version; dev_dbg(xpc_part, " remote_vars_version = 0x%x\n", - part->remote_vars_version); + part_sn2->remote_vars_version); } /* @@ -807,6 +886,7 @@ xpc_identify_activate_IRQ_req_sn2(int nasid) unsigned long remote_rp_stamp = 0; short partid; struct xpc_partition *part; + struct xpc_partition_sn2 *part_sn2; enum xp_retval ret; /* pull over the reserved page structure */ @@ -822,11 +902,11 @@ xpc_identify_activate_IRQ_req_sn2(int nasid) remote_vars_pa = remote_rp->sn.vars_pa; remote_rp_version = remote_rp->version; - if (XPC_SUPPORTS_RP_STAMP(remote_rp_version)) - remote_rp_stamp = remote_rp->stamp; + remote_rp_stamp = remote_rp->stamp; partid = remote_rp->SAL_partid; part = &xpc_partitions[partid]; + part_sn2 = &part->sn.sn2; /* pull over the cross partition variables */ @@ -834,7 +914,6 @@ xpc_identify_activate_IRQ_req_sn2(int nasid) ret = xpc_get_remote_vars_sn2(remote_vars_pa, remote_vars); if (ret != xpSuccess) { - dev_warn(xpc_part, "unable to get XPC variables from nasid %d, " "which sent interrupt, reason=%d\n", nasid, ret); @@ -855,18 +934,12 @@ xpc_identify_activate_IRQ_req_sn2(int nasid) &remote_rp_stamp, remote_rp_pa, remote_vars_pa, remote_vars); - if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) { - if (xpc_partition_disengage_requested(1UL << partid)) { - /* - * Other side is waiting on us to disengage, - * even though we already have. - */ - return; - } - - } else { - /* other side doesn't support disengage requests */ - xpc_clear_partition_disengage_request(1UL << partid); + if (xpc_partition_deactivation_requested_sn2(partid)) { + /* + * Other side is waiting on us to deactivate even though + * we already have. + */ + return; } xpc_activate_partition(part); @@ -874,93 +947,30 @@ xpc_identify_activate_IRQ_req_sn2(int nasid) } DBUG_ON(part->remote_rp_version == 0); - DBUG_ON(part->remote_vars_version == 0); - - if (!XPC_SUPPORTS_RP_STAMP(part->remote_rp_version)) { - DBUG_ON(XPC_SUPPORTS_DISENGAGE_REQUEST(part-> - remote_vars_version)); - - if (!XPC_SUPPORTS_RP_STAMP(remote_rp_version)) { - DBUG_ON(XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars-> - version)); - /* see if the other side rebooted */ - if (part->remote_amos_page_pa == - remote_vars->amos_page_pa && - xpc_hb_allowed(sn_partition_id, - &remote_vars->heartbeating_to_mask)) { - /* doesn't look that way, so ignore the IPI */ - return; - } - } + DBUG_ON(part_sn2->remote_vars_version == 0); - /* - * Other side rebooted and previous XPC didn't support the - * disengage request, so we don't need to do anything special. - */ + if (remote_rp_stamp != part->remote_rp_stamp) { - xpc_update_partition_info_sn2(part, remote_rp_version, - &remote_rp_stamp, remote_rp_pa, - remote_vars_pa, remote_vars); - part->reactivate_nasid = nasid; - XPC_DEACTIVATE_PARTITION(part, xpReactivating); - return; - } + /* the other side rebooted */ - DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)); - - if (!XPC_SUPPORTS_RP_STAMP(remote_rp_version)) { - DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->version)); - - /* - * Other side rebooted and previous XPC did support the - * disengage request, but the new one doesn't. - */ - - xpc_clear_partition_engaged(1UL << partid); - xpc_clear_partition_disengage_request(1UL << partid); + DBUG_ON(xpc_partition_engaged_sn2(partid)); + DBUG_ON(xpc_partition_deactivation_requested_sn2(partid)); xpc_update_partition_info_sn2(part, remote_rp_version, &remote_rp_stamp, remote_rp_pa, remote_vars_pa, remote_vars); reactivate = 1; - - } else { - DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->version)); - - if (remote_rp_stamp != part->remote_rp_stamp) { - - /* - * Other side rebooted and the previous XPC did support - * the disengage request, as does the new one. - */ - - DBUG_ON(xpc_partition_engaged(1UL << partid)); - DBUG_ON(xpc_partition_disengage_requested(1UL << - partid)); - - xpc_update_partition_info_sn2(part, remote_rp_version, - &remote_rp_stamp, - remote_rp_pa, - remote_vars_pa, - remote_vars); - reactivate = 1; - } } - if (part->disengage_request_timeout > 0 && - !xpc_partition_disengaged(part)) { + if (part->disengage_timeout > 0 && !xpc_partition_disengaged(part)) { /* still waiting on other side to disengage from us */ return; } - if (reactivate) { - part->reactivate_nasid = nasid; + if (reactivate) XPC_DEACTIVATE_PARTITION(part, xpReactivating); - - } else if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version) && - xpc_partition_disengage_requested(1UL << partid)) { + else if (xpc_partition_deactivation_requested_sn2(partid)) XPC_DEACTIVATE_PARTITION(part, xpOtherGoingDown); - } } /* @@ -1038,6 +1048,7 @@ xpc_process_activate_IRQ_rcvd_sn2(int n_IRQs_expected) static enum xp_retval xpc_setup_infrastructure_sn2(struct xpc_partition *part) { + struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; enum xp_retval retval; int ret; int cpuid; @@ -1060,28 +1071,29 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) /* allocate all the required GET/PUT values */ - part->local_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, - GFP_KERNEL, - &part->local_GPs_base); - if (part->local_GPs == NULL) { + part_sn2->local_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, + GFP_KERNEL, + &part_sn2-> + local_GPs_base); + if (part_sn2->local_GPs == NULL) { dev_err(xpc_chan, "can't get memory for local get/put " "values\n"); retval = xpNoMemory; goto out_1; } - part->remote_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, - GFP_KERNEL, - &part-> - remote_GPs_base); - if (part->remote_GPs == NULL) { + part_sn2->remote_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, + GFP_KERNEL, + &part_sn2-> + remote_GPs_base); + if (part_sn2->remote_GPs == NULL) { dev_err(xpc_chan, "can't get memory for remote get/put " "values\n"); retval = xpNoMemory; goto out_2; } - part->remote_GPs_pa = 0; + part_sn2->remote_GPs_pa = 0; /* allocate all the required open and close args */ @@ -1103,22 +1115,23 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) goto out_4; } - part->remote_openclose_args_pa = 0; + part_sn2->remote_openclose_args_pa = 0; - part->local_IPI_amo_va = xpc_IPI_init_sn2(partid); + part_sn2->local_IPI_amo_va = xpc_IPI_init_sn2(partid); part->local_IPI_amo = 0; spin_lock_init(&part->IPI_lock); - part->remote_IPI_nasid = 0; - part->remote_IPI_phys_cpuid = 0; - part->remote_IPI_amo_va = NULL; + part_sn2->remote_IPI_nasid = 0; + part_sn2->remote_IPI_phys_cpuid = 0; + part_sn2->remote_IPI_amo_va = NULL; atomic_set(&part->channel_mgr_requests, 1); init_waitqueue_head(&part->channel_mgr_wq); - sprintf(part->IPI_owner, "xpc%02d", partid); - ret = request_irq(SGI_XPC_NOTIFY, xpc_notify_IRQ_handler, IRQF_SHARED, - part->IPI_owner, (void *)(u64)partid); + sprintf(part_sn2->IPI_owner, "xpc%02d", partid); + ret = request_irq(SGI_XPC_NOTIFY, xpc_handle_notify_IRQ_sn2, + IRQF_SHARED, part_sn2->IPI_owner, + (void *)(u64)partid); if (ret != 0) { dev_err(xpc_chan, "can't register NOTIFY IRQ handler, " "errno=%d\n", -ret); @@ -1127,9 +1140,10 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) } /* Setup a timer to check for dropped IPIs */ - timer = &part->dropped_IPI_timer; + timer = &part_sn2->dropped_notify_IRQ_timer; init_timer(timer); - timer->function = (void (*)(unsigned long))xpc_dropped_IPI_check; + timer->function = + (void (*)(unsigned long))xpc_dropped_notify_IRQ_check_sn2; timer->data = (unsigned long)part; timer->expires = jiffies + XPC_P_DROPPED_IPI_WAIT_INTERVAL; add_timer(timer); @@ -1146,7 +1160,7 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) ch->number = ch_number; ch->flags = XPC_C_DISCONNECTED; - ch->local_GP = &part->local_GPs[ch_number]; + ch->sn.sn2.local_GP = &part_sn2->local_GPs[ch_number]; ch->local_openclose_args = &part->local_openclose_args[ch_number]; @@ -1158,7 +1172,7 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) atomic_set(&ch->n_to_notify, 0); spin_lock_init(&ch->lock); - mutex_init(&ch->msg_to_pull_mutex); + mutex_init(&ch->sn.sn2.msg_to_pull_mutex); init_completion(&ch->wdisconnect_wait); atomic_set(&ch->n_on_msg_allocate_wq, 0); @@ -1179,10 +1193,10 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) * The setting of the magic # indicates that these per partition * specific variables are ready to be used. */ - xpc_vars_part[partid].GPs_pa = __pa(part->local_GPs); + xpc_vars_part[partid].GPs_pa = __pa(part_sn2->local_GPs); xpc_vars_part[partid].openclose_args_pa = __pa(part->local_openclose_args); - xpc_vars_part[partid].IPI_amo_pa = __pa(part->local_IPI_amo_va); + xpc_vars_part[partid].IPI_amo_pa = __pa(part_sn2->local_IPI_amo_va); cpuid = raw_smp_processor_id(); /* any CPU in this partition will do */ xpc_vars_part[partid].IPI_nasid = cpuid_to_nasid(cpuid); xpc_vars_part[partid].IPI_phys_cpuid = cpu_physical_id(cpuid); @@ -1199,11 +1213,11 @@ out_4: kfree(part->local_openclose_args_base); part->local_openclose_args = NULL; out_3: - kfree(part->remote_GPs_base); - part->remote_GPs = NULL; + kfree(part_sn2->remote_GPs_base); + part_sn2->remote_GPs = NULL; out_2: - kfree(part->local_GPs_base); - part->local_GPs = NULL; + kfree(part_sn2->local_GPs_base); + part_sn2->local_GPs = NULL; out_1: kfree(part->channels); part->channels = NULL; @@ -1217,6 +1231,7 @@ out_1: static void xpc_teardown_infrastructure_sn2(struct xpc_partition *part) { + struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; short partid = XPC_PARTID(part); /* @@ -1248,19 +1263,19 @@ xpc_teardown_infrastructure_sn2(struct xpc_partition *part) part->setup_state = XPC_P_TORNDOWN; /* in case we've still got outstanding timers registered... */ - del_timer_sync(&part->dropped_IPI_timer); + del_timer_sync(&part_sn2->dropped_notify_IRQ_timer); kfree(part->remote_openclose_args_base); part->remote_openclose_args = NULL; kfree(part->local_openclose_args_base); part->local_openclose_args = NULL; - kfree(part->remote_GPs_base); - part->remote_GPs = NULL; - kfree(part->local_GPs_base); - part->local_GPs = NULL; + kfree(part_sn2->remote_GPs_base); + part_sn2->remote_GPs = NULL; + kfree(part_sn2->local_GPs_base); + part_sn2->local_GPs = NULL; kfree(part->channels); part->channels = NULL; - part->local_IPI_amo_va = NULL; + part_sn2->local_IPI_amo_va = NULL; } /* @@ -1300,6 +1315,7 @@ xpc_pull_remote_cachelines_sn2(struct xpc_partition *part, void *dst, static enum xp_retval xpc_pull_remote_vars_part_sn2(struct xpc_partition *part) { + struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; u8 buffer[L1_CACHE_BYTES * 2]; struct xpc_vars_part_sn2 *pulled_entry_cacheline = (struct xpc_vars_part_sn2 *)L1_CACHE_ALIGN((u64)buffer); @@ -1310,11 +1326,11 @@ xpc_pull_remote_vars_part_sn2(struct xpc_partition *part) /* pull the cacheline that contains the variables we're interested in */ - DBUG_ON(part->remote_vars_part_pa != - L1_CACHE_ALIGN(part->remote_vars_part_pa)); + DBUG_ON(part_sn2->remote_vars_part_pa != + L1_CACHE_ALIGN(part_sn2->remote_vars_part_pa)); DBUG_ON(sizeof(struct xpc_vars_part_sn2) != L1_CACHE_BYTES / 2); - remote_entry_pa = part->remote_vars_part_pa + + remote_entry_pa = part_sn2->remote_vars_part_pa + sn_partition_id * sizeof(struct xpc_vars_part_sn2); remote_entry_cacheline_pa = (remote_entry_pa & ~(L1_CACHE_BYTES - 1)); @@ -1364,13 +1380,13 @@ xpc_pull_remote_vars_part_sn2(struct xpc_partition *part) /* the variables we imported look to be valid */ - part->remote_GPs_pa = pulled_entry->GPs_pa; - part->remote_openclose_args_pa = + part_sn2->remote_GPs_pa = pulled_entry->GPs_pa; + part_sn2->remote_openclose_args_pa = pulled_entry->openclose_args_pa; - part->remote_IPI_amo_va = + part_sn2->remote_IPI_amo_va = (AMO_t *)__va(pulled_entry->IPI_amo_pa); - part->remote_IPI_nasid = pulled_entry->IPI_nasid; - part->remote_IPI_phys_cpuid = pulled_entry->IPI_phys_cpuid; + part_sn2->remote_IPI_nasid = pulled_entry->IPI_nasid; + part_sn2->remote_IPI_phys_cpuid = pulled_entry->IPI_phys_cpuid; if (part->nchannels > pulled_entry->nchannels) part->nchannels = pulled_entry->nchannels; @@ -1394,6 +1410,7 @@ xpc_pull_remote_vars_part_sn2(struct xpc_partition *part) static enum xp_retval xpc_make_first_contact_sn2(struct xpc_partition *part) { + struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; enum xp_retval ret; /* @@ -1406,7 +1423,7 @@ xpc_make_first_contact_sn2(struct xpc_partition *part) * we should get the same page for remote_amos_page_pa after module * reloads and system reboots. */ - if (sn_register_xp_addr_region(part->remote_amos_page_pa, + if (sn_register_xp_addr_region(part_sn2->remote_amos_page_pa, PAGE_SIZE, 1) < 0) { dev_warn(xpc_part, "xpc_activating(%d) failed to register " "xp_addr region\n", XPC_PARTID(part)); @@ -1416,7 +1433,14 @@ xpc_make_first_contact_sn2(struct xpc_partition *part) return ret; } - xpc_IPI_send_activated(part); + /* + * Send activate IRQ to get other side to activate if they've not + * already begun to do so. + */ + xpc_activate_IRQ_send_sn2(part_sn2->remote_amos_page_pa, + cnodeid_to_nasid(0), + part_sn2->activate_IRQ_nasid, + part_sn2->activate_IRQ_phys_cpuid); while ((ret = xpc_pull_remote_vars_part_sn2(part)) != xpSuccess) { if (ret != xpRetry) { @@ -1443,6 +1467,7 @@ xpc_make_first_contact_sn2(struct xpc_partition *part) static u64 xpc_get_IPI_flags_sn2(struct xpc_partition *part) { + struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; unsigned long irq_flags; u64 IPI_amo; enum xp_retval ret; @@ -1459,9 +1484,9 @@ xpc_get_IPI_flags_sn2(struct xpc_partition *part) spin_unlock_irqrestore(&part->IPI_lock, irq_flags); if (XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(IPI_amo)) { - ret = xpc_pull_remote_cachelines_sn2(part, - part->remote_openclose_args, - (void *)part-> + ret = xpc_pull_remote_cachelines_sn2(part, part-> + remote_openclose_args, + (void *)part_sn2-> remote_openclose_args_pa, XPC_OPENCLOSE_ARGS_SIZE); if (ret != xpSuccess) { @@ -1477,8 +1502,8 @@ xpc_get_IPI_flags_sn2(struct xpc_partition *part) } if (XPC_ANY_MSG_IPI_FLAGS_SET(IPI_amo)) { - ret = xpc_pull_remote_cachelines_sn2(part, part->remote_GPs, - (void *)part->remote_GPs_pa, + ret = xpc_pull_remote_cachelines_sn2(part, part_sn2->remote_GPs, + (void *)part_sn2->remote_GPs_pa, XPC_GP_SIZE); if (ret != xpSuccess) { XPC_DEACTIVATE_PARTITION(part, ret); @@ -1494,28 +1519,220 @@ xpc_get_IPI_flags_sn2(struct xpc_partition *part) return IPI_amo; } +/* + * Notify those who wanted to be notified upon delivery of their message. + */ +static void +xpc_notify_senders_sn2(struct xpc_channel *ch, enum xp_retval reason, s64 put) +{ + struct xpc_notify *notify; + u8 notify_type; + s64 get = ch->sn.sn2.w_remote_GP.get - 1; + + while (++get < put && atomic_read(&ch->n_to_notify) > 0) { + + notify = &ch->notify_queue[get % ch->local_nentries]; + + /* + * See if the notify entry indicates it was associated with + * a message who's sender wants to be notified. It is possible + * that it is, but someone else is doing or has done the + * notification. + */ + notify_type = notify->type; + if (notify_type == 0 || + cmpxchg(¬ify->type, notify_type, 0) != notify_type) { + continue; + } + + DBUG_ON(notify_type != XPC_N_CALL); + + atomic_dec(&ch->n_to_notify); + + if (notify->func != NULL) { + dev_dbg(xpc_chan, "notify->func() called, notify=0x%p, " + "msg_number=%ld, partid=%d, channel=%d\n", + (void *)notify, get, ch->partid, ch->number); + + notify->func(reason, ch->partid, ch->number, + notify->key); + + dev_dbg(xpc_chan, "notify->func() returned, " + "notify=0x%p, msg_number=%ld, partid=%d, " + "channel=%d\n", (void *)notify, get, + ch->partid, ch->number); + } + } +} + +static void +xpc_notify_senders_of_disconnect_sn2(struct xpc_channel *ch) +{ + xpc_notify_senders_sn2(ch, ch->reason, ch->sn.sn2.w_local_GP.put); +} + +/* + * Clear some of the msg flags in the local message queue. + */ +static inline void +xpc_clear_local_msgqueue_flags_sn2(struct xpc_channel *ch) +{ + struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; + struct xpc_msg *msg; + s64 get; + + get = ch_sn2->w_remote_GP.get; + do { + msg = (struct xpc_msg *)((u64)ch->local_msgqueue + + (get % ch->local_nentries) * + ch->msg_size); + msg->flags = 0; + } while (++get < ch_sn2->remote_GP.get); +} + +/* + * Clear some of the msg flags in the remote message queue. + */ +static inline void +xpc_clear_remote_msgqueue_flags_sn2(struct xpc_channel *ch) +{ + struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; + struct xpc_msg *msg; + s64 put; + + put = ch_sn2->w_remote_GP.put; + do { + msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + + (put % ch->remote_nentries) * + ch->msg_size); + msg->flags = 0; + } while (++put < ch_sn2->remote_GP.put); +} + +static void +xpc_process_msg_IPI_sn2(struct xpc_partition *part, int ch_number) +{ + struct xpc_channel *ch = &part->channels[ch_number]; + struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; + int nmsgs_sent; + + ch_sn2->remote_GP = part->sn.sn2.remote_GPs[ch_number]; + + /* See what, if anything, has changed for each connected channel */ + + xpc_msgqueue_ref(ch); + + if (ch_sn2->w_remote_GP.get == ch_sn2->remote_GP.get && + ch_sn2->w_remote_GP.put == ch_sn2->remote_GP.put) { + /* nothing changed since GPs were last pulled */ + xpc_msgqueue_deref(ch); + return; + } + + if (!(ch->flags & XPC_C_CONNECTED)) { + xpc_msgqueue_deref(ch); + return; + } + + /* + * First check to see if messages recently sent by us have been + * received by the other side. (The remote GET value will have + * changed since we last looked at it.) + */ + + if (ch_sn2->w_remote_GP.get != ch_sn2->remote_GP.get) { + + /* + * We need to notify any senders that want to be notified + * that their sent messages have been received by their + * intended recipients. We need to do this before updating + * w_remote_GP.get so that we don't allocate the same message + * queue entries prematurely (see xpc_allocate_msg()). + */ + if (atomic_read(&ch->n_to_notify) > 0) { + /* + * Notify senders that messages sent have been + * received and delivered by the other side. + */ + xpc_notify_senders_sn2(ch, xpMsgDelivered, + ch_sn2->remote_GP.get); + } + + /* + * Clear msg->flags in previously sent messages, so that + * they're ready for xpc_allocate_msg(). + */ + xpc_clear_local_msgqueue_flags_sn2(ch); + + ch_sn2->w_remote_GP.get = ch_sn2->remote_GP.get; + + dev_dbg(xpc_chan, "w_remote_GP.get changed to %ld, partid=%d, " + "channel=%d\n", ch_sn2->w_remote_GP.get, ch->partid, + ch->number); + + /* + * If anyone was waiting for message queue entries to become + * available, wake them up. + */ + if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) + wake_up(&ch->msg_allocate_wq); + } + + /* + * Now check for newly sent messages by the other side. (The remote + * PUT value will have changed since we last looked at it.) + */ + + if (ch_sn2->w_remote_GP.put != ch_sn2->remote_GP.put) { + /* + * Clear msg->flags in previously received messages, so that + * they're ready for xpc_get_deliverable_msg(). + */ + xpc_clear_remote_msgqueue_flags_sn2(ch); + + ch_sn2->w_remote_GP.put = ch_sn2->remote_GP.put; + + dev_dbg(xpc_chan, "w_remote_GP.put changed to %ld, partid=%d, " + "channel=%d\n", ch_sn2->w_remote_GP.put, ch->partid, + ch->number); + + nmsgs_sent = ch_sn2->w_remote_GP.put - ch_sn2->w_local_GP.get; + if (nmsgs_sent > 0) { + dev_dbg(xpc_chan, "msgs waiting to be copied and " + "delivered=%d, partid=%d, channel=%d\n", + nmsgs_sent, ch->partid, ch->number); + + if (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) + xpc_activate_kthreads(ch, nmsgs_sent); + } + } + + xpc_msgqueue_deref(ch); +} + static struct xpc_msg * xpc_pull_remote_msg_sn2(struct xpc_channel *ch, s64 get) { struct xpc_partition *part = &xpc_partitions[ch->partid]; + struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; struct xpc_msg *remote_msg, *msg; u32 msg_index, nmsgs; u64 msg_offset; enum xp_retval ret; - if (mutex_lock_interruptible(&ch->msg_to_pull_mutex) != 0) { + if (mutex_lock_interruptible(&ch_sn2->msg_to_pull_mutex) != 0) { /* we were interrupted by a signal */ return NULL; } - while (get >= ch->next_msg_to_pull) { + while (get >= ch_sn2->next_msg_to_pull) { /* pull as many messages as are ready and able to be pulled */ - msg_index = ch->next_msg_to_pull % ch->remote_nentries; + msg_index = ch_sn2->next_msg_to_pull % ch->remote_nentries; - DBUG_ON(ch->next_msg_to_pull >= ch->w_remote_GP.put); - nmsgs = ch->w_remote_GP.put - ch->next_msg_to_pull; + DBUG_ON(ch_sn2->next_msg_to_pull >= ch_sn2->w_remote_GP.put); + nmsgs = ch_sn2->w_remote_GP.put - ch_sn2->next_msg_to_pull; if (msg_index + nmsgs > ch->remote_nentries) { /* ignore the ones that wrap the msg queue for now */ nmsgs = ch->remote_nentries - msg_index; @@ -1532,19 +1749,19 @@ xpc_pull_remote_msg_sn2(struct xpc_channel *ch, s64 get) dev_dbg(xpc_chan, "failed to pull %d msgs starting with" " msg %ld from partition %d, channel=%d, " - "ret=%d\n", nmsgs, ch->next_msg_to_pull, + "ret=%d\n", nmsgs, ch_sn2->next_msg_to_pull, ch->partid, ch->number, ret); XPC_DEACTIVATE_PARTITION(part, ret); - mutex_unlock(&ch->msg_to_pull_mutex); + mutex_unlock(&ch_sn2->msg_to_pull_mutex); return NULL; } - ch->next_msg_to_pull += nmsgs; + ch_sn2->next_msg_to_pull += nmsgs; } - mutex_unlock(&ch->msg_to_pull_mutex); + mutex_unlock(&ch_sn2->msg_to_pull_mutex); /* return the message we were looking for */ msg_offset = (get % ch->remote_nentries) * ch->msg_size; @@ -1553,12 +1770,19 @@ xpc_pull_remote_msg_sn2(struct xpc_channel *ch, s64 get) return msg; } +static int +xpc_n_of_deliverable_msgs_sn2(struct xpc_channel *ch) +{ + return ch->sn.sn2.w_remote_GP.put - ch->sn.sn2.w_local_GP.get; +} + /* * Get a message to be delivered. */ static struct xpc_msg * xpc_get_deliverable_msg_sn2(struct xpc_channel *ch) { + struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; struct xpc_msg *msg = NULL; s64 get; @@ -1566,9 +1790,9 @@ xpc_get_deliverable_msg_sn2(struct xpc_channel *ch) if (ch->flags & XPC_C_DISCONNECTING) break; - get = ch->w_local_GP.get; + get = ch_sn2->w_local_GP.get; rmb(); /* guarantee that .get loads before .put */ - if (get == ch->w_remote_GP.put) + if (get == ch_sn2->w_remote_GP.put) break; /* There are messages waiting to be pulled and delivered. @@ -1578,7 +1802,7 @@ xpc_get_deliverable_msg_sn2(struct xpc_channel *ch) * to try again for the next one. */ - if (cmpxchg(&ch->w_local_GP.get, get, get + 1) == get) { + if (cmpxchg(&ch_sn2->w_local_GP.get, get, get + 1) == get) { /* we got the entry referenced by get */ dev_dbg(xpc_chan, "w_local_GP.get changed to %ld, " @@ -1609,6 +1833,7 @@ xpc_get_deliverable_msg_sn2(struct xpc_channel *ch) static void xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put) { + struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; struct xpc_msg *msg; s64 put = initial_put + 1; int send_IPI = 0; @@ -1616,7 +1841,7 @@ xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put) while (1) { while (1) { - if (put == ch->w_local_GP.put) + if (put == ch_sn2->w_local_GP.put) break; msg = (struct xpc_msg *)((u64)ch->local_msgqueue + @@ -1634,10 +1859,10 @@ xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put) break; } - if (cmpxchg_rel(&ch->local_GP->put, initial_put, put) != + if (cmpxchg_rel(&ch_sn2->local_GP->put, initial_put, put) != initial_put) { /* someone else beat us to it */ - DBUG_ON(ch->local_GP->put < initial_put); + DBUG_ON(ch_sn2->local_GP->put < initial_put); break; } @@ -1657,7 +1882,7 @@ xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put) } if (send_IPI) - xpc_IPI_send_msgrequest_sn2(ch); + xpc_send_channel_msgrequest_sn2(ch); } /* @@ -1668,6 +1893,7 @@ static enum xp_retval xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags, struct xpc_msg **address_of_msg) { + struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; struct xpc_msg *msg; enum xp_retval ret; s64 put; @@ -1681,9 +1907,9 @@ xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags, while (1) { - put = ch->w_local_GP.put; + put = ch_sn2->w_local_GP.put; rmb(); /* guarantee that .put loads before .get */ - if (put - ch->w_remote_GP.get < ch->local_nentries) { + if (put - ch_sn2->w_remote_GP.get < ch->local_nentries) { /* There are available message entries. We need to try * to secure one for ourselves. We'll do this by trying @@ -1691,7 +1917,8 @@ xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags, * doesn't beat us to it. If they do, we'll have to * try again. */ - if (cmpxchg(&ch->w_local_GP.put, put, put + 1) == put) { + if (cmpxchg(&ch_sn2->w_local_GP.put, put, put + 1) == + put) { /* we got the entry referenced by put */ break; } @@ -1708,7 +1935,7 @@ xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags, * GP values as if an IPI was sent by the other side. */ if (ret == xpTimeout) - xpc_IPI_send_local_msgrequest_sn2(ch); + xpc_send_channel_local_msgrequest_sn2(ch); if (flags & XPC_NOWAIT) return xpNoWait; @@ -1810,13 +2037,13 @@ xpc_send_msg_sn2(struct xpc_channel *ch, u32 flags, void *payload, /* * The preceding store of msg->flags must occur before the following - * load of ch->local_GP->put. + * load of local_GP->put. */ mb(); /* see if the message is next in line to be sent, if so send it */ - put = ch->local_GP->put; + put = ch->sn.sn2.local_GP->put; if (put == msg_number) xpc_send_msgs_sn2(ch, put); @@ -1833,6 +2060,7 @@ out_1: static void xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) { + struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; struct xpc_msg *msg; s64 get = initial_get + 1; int send_IPI = 0; @@ -1840,7 +2068,7 @@ xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) while (1) { while (1) { - if (get == ch->w_local_GP.get) + if (get == ch_sn2->w_local_GP.get) break; msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + @@ -1859,10 +2087,10 @@ xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) break; } - if (cmpxchg_rel(&ch->local_GP->get, initial_get, get) != + if (cmpxchg_rel(&ch_sn2->local_GP->get, initial_get, get) != initial_get) { /* someone else beat us to it */ - DBUG_ON(ch->local_GP->get <= initial_get); + DBUG_ON(ch_sn2->local_GP->get <= initial_get); break; } @@ -1882,7 +2110,7 @@ xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) } if (send_IPI) - xpc_IPI_send_msgrequest_sn2(ch); + xpc_send_channel_msgrequest_sn2(ch); } static void @@ -1902,7 +2130,7 @@ xpc_received_msg_sn2(struct xpc_channel *ch, struct xpc_msg *msg) /* * The preceding store of msg->flags must occur before the following - * load of ch->local_GP->get. + * load of local_GP->get. */ mb(); @@ -1910,7 +2138,7 @@ xpc_received_msg_sn2(struct xpc_channel *ch, struct xpc_msg *msg) * See if this message is next in line to be acknowledged as having * been delivered. */ - get = ch->local_GP->get; + get = ch->sn.sn2.local_GP->get; if (get == msg_number) xpc_acknowledge_msgs_sn2(ch, get, msg->flags); } @@ -1928,36 +2156,35 @@ xpc_init_sn2(void) xpc_heartbeat_exit = xpc_heartbeat_exit_sn2; xpc_check_remote_hb = xpc_check_remote_hb_sn2; - xpc_initiate_partition_activation = - xpc_initiate_partition_activation_sn2; + xpc_request_partition_activation = xpc_request_partition_activation_sn2; + xpc_request_partition_reactivation = + xpc_request_partition_reactivation_sn2; + xpc_request_partition_deactivation = + xpc_request_partition_deactivation_sn2; + xpc_cancel_partition_deactivation_request = + xpc_cancel_partition_deactivation_request_sn2; + xpc_process_activate_IRQ_rcvd = xpc_process_activate_IRQ_rcvd_sn2; xpc_setup_infrastructure = xpc_setup_infrastructure_sn2; xpc_teardown_infrastructure = xpc_teardown_infrastructure_sn2; xpc_make_first_contact = xpc_make_first_contact_sn2; xpc_get_IPI_flags = xpc_get_IPI_flags_sn2; + xpc_notify_senders_of_disconnect = xpc_notify_senders_of_disconnect_sn2; + xpc_process_msg_IPI = xpc_process_msg_IPI_sn2; + xpc_n_of_deliverable_msgs = xpc_n_of_deliverable_msgs_sn2; xpc_get_deliverable_msg = xpc_get_deliverable_msg_sn2; - xpc_mark_partition_engaged = xpc_mark_partition_engaged_sn2; - xpc_mark_partition_disengaged = xpc_mark_partition_disengaged_sn2; - xpc_request_partition_disengage = xpc_request_partition_disengage_sn2; - xpc_cancel_partition_disengage_request = - xpc_cancel_partition_disengage_request_sn2; + xpc_indicate_partition_engaged = xpc_indicate_partition_engaged_sn2; xpc_partition_engaged = xpc_partition_engaged_sn2; - xpc_partition_disengage_requested = - xpc_partition_disengage_requested_sn2; - xpc_clear_partition_engaged = xpc_clear_partition_engaged_sn2; - xpc_clear_partition_disengage_request = - xpc_clear_partition_disengage_request_sn2; - - xpc_IPI_send_local_activate = xpc_IPI_send_local_activate_sn2; - xpc_IPI_send_activated = xpc_IPI_send_activated_sn2; - xpc_IPI_send_local_reactivate = xpc_IPI_send_local_reactivate_sn2; - xpc_IPI_send_disengage = xpc_IPI_send_disengage_sn2; - - xpc_IPI_send_closerequest = xpc_IPI_send_closerequest_sn2; - xpc_IPI_send_closereply = xpc_IPI_send_closereply_sn2; - xpc_IPI_send_openrequest = xpc_IPI_send_openrequest_sn2; - xpc_IPI_send_openreply = xpc_IPI_send_openreply_sn2; + xpc_any_partition_engaged = xpc_any_partition_engaged_sn2; + xpc_indicate_partition_disengaged = + xpc_indicate_partition_disengaged_sn2; + xpc_assume_partition_disengaged = xpc_assume_partition_disengaged_sn2; + + xpc_send_channel_closerequest = xpc_send_channel_closerequest_sn2; + xpc_send_channel_closereply = xpc_send_channel_closereply_sn2; + xpc_send_channel_openrequest = xpc_send_channel_openrequest_sn2; + xpc_send_channel_openreply = xpc_send_channel_openreply_sn2; xpc_send_msg = xpc_send_msg_sn2; xpc_received_msg = xpc_received_msg_sn2; diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index 32c577b8d0d..c53b229cb04 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c @@ -63,8 +63,8 @@ xpc_heartbeat_exit_uv(void) } static void -xpc_initiate_partition_activation_uv(struct xpc_rsvd_page *remote_rp, - u64 remote_rp_pa, int nasid) +xpc_request_partition_activation_uv(struct xpc_rsvd_page *remote_rp, + u64 remote_rp_pa, int nasid) { short partid = remote_rp->SAL_partid; struct xpc_partition *part = &xpc_partitions[partid]; @@ -78,6 +78,12 @@ xpc_initiate_partition_activation_uv(struct xpc_rsvd_page *remote_rp, xpc_IPI_send_local_activate_uv(part); } +static void +xpc_request_partition_reactivation_uv(struct xpc_partition *part) +{ + xpc_IPI_send_local_activate_uv(part); +} + /* * Setup the infrastructure necessary to support XPartition Communication * between the specified remote partition and the local one. @@ -128,8 +134,9 @@ xpc_init_uv(void) xpc_increment_heartbeat = xpc_increment_heartbeat_uv; xpc_heartbeat_init = xpc_heartbeat_init_uv; xpc_heartbeat_exit = xpc_heartbeat_exit_uv; - xpc_initiate_partition_activation = - xpc_initiate_partition_activation_uv; + xpc_request_partition_activation = xpc_request_partition_activation_uv; + xpc_request_partition_reactivation = + xpc_request_partition_reactivation_uv; xpc_setup_infrastructure = xpc_setup_infrastructure_uv; xpc_teardown_infrastructure = xpc_teardown_infrastructure_uv; xpc_make_first_contact = xpc_make_first_contact_uv; -- cgit v1.2.3 From 7fb5e59d63deda89a8eefdbd5b3c8d622076afd4 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:10 -0700 Subject: sgi-xp: separate chctl_flags from XPC's notify IRQ Tie current IPI references to either XPC's notify IRQ or channel control flags. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xpc.h | 124 +++++++++------- drivers/misc/sgi-xp/xpc_channel.c | 135 +++++++++-------- drivers/misc/sgi-xp/xpc_main.c | 59 ++++---- drivers/misc/sgi-xp/xpc_sn2.c | 301 +++++++++++++++++++------------------- drivers/misc/sgi-xp/xpc_uv.c | 10 +- 5 files changed, 327 insertions(+), 302 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index b04cfbed958..26a1725f68a 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -186,9 +186,10 @@ struct xpc_vars_part_sn2 { u64 openclose_args_pa; /* physical address of open and close args */ u64 GPs_pa; /* physical address of Get/Put values */ - u64 IPI_amo_pa; /* physical address of IPI AMO_t structure */ - int IPI_nasid; /* nasid of where to send IPIs */ - int IPI_phys_cpuid; /* physical CPU ID of where to send IPIs */ + u64 chctl_amo_pa; /* physical address of chctl flags' AMO_t */ + + int notify_IRQ_nasid; /* nasid of where to send notify IRQs */ + int notify_IRQ_phys_cpuid; /* CPUID of where to send notify IRQs */ u8 nchannels; /* #of defined channels supported */ @@ -407,7 +408,7 @@ struct xpc_channel { atomic_t n_on_msg_allocate_wq; /* #on msg allocation wait queue */ wait_queue_head_t msg_allocate_wq; /* msg allocation wait queue */ - u8 delayed_IPI_flags; /* IPI flags received, but delayed */ + u8 delayed_chctl_flags; /* chctl flags received, but delayed */ /* action until channel disconnected */ /* queue of msg senders who want to be notified when msg received */ @@ -469,6 +470,54 @@ struct xpc_channel { 0x00020000 /* disconnecting callout completed */ #define XPC_C_WDISCONNECT 0x00040000 /* waiting for channel disconnect */ +/* + * The channel control flags (chctl) union consists of a 64-bit variable which + * is divided up into eight bytes, ordered from right to left. Byte zero + * pertains to channel 0, byte one to channel 1, and so on. Each channel's byte + * can have one or more of the chctl flags set in it. + */ + +union xpc_channel_ctl_flags { + u64 all_flags; + u8 flags[XPC_MAX_NCHANNELS]; +}; + +/* chctl flags */ +#define XPC_CHCTL_CLOSEREQUEST 0x01 +#define XPC_CHCTL_CLOSEREPLY 0x02 +#define XPC_CHCTL_OPENREQUEST 0x04 +#define XPC_CHCTL_OPENREPLY 0x08 +#define XPC_CHCTL_MSGREQUEST 0x10 + +#define XPC_OPENCLOSE_CHCTL_FLAGS \ + (XPC_CHCTL_CLOSEREQUEST | XPC_CHCTL_CLOSEREPLY | \ + XPC_CHCTL_OPENREQUEST | XPC_CHCTL_OPENREPLY) +#define XPC_MSG_CHCTL_FLAGS XPC_CHCTL_MSGREQUEST + +static inline int +xpc_any_openclose_chctl_flags_set(union xpc_channel_ctl_flags *chctl) +{ + int ch_number; + + for (ch_number = 0; ch_number < XPC_MAX_NCHANNELS; ch_number++) { + if (chctl->flags[ch_number] & XPC_OPENCLOSE_CHCTL_FLAGS) + return 1; + } + return 0; +} + +static inline int +xpc_any_msg_chctl_flags_set(union xpc_channel_ctl_flags *chctl) +{ + int ch_number; + + for (ch_number = 0; ch_number < XPC_MAX_NCHANNELS; ch_number++) { + if (chctl->flags[ch_number] & XPC_MSG_CHCTL_FLAGS) + return 1; + } + return 0; +} + /* * Manages channels on a partition basis. There is one of these structures * for each partition (a partition will never utilize the structure that @@ -494,12 +543,12 @@ struct xpc_partition_sn2 { u64 remote_openclose_args_pa; /* phys addr of remote's args */ - int remote_IPI_nasid; /* nasid of where to send IPIs */ - int remote_IPI_phys_cpuid; /* phys CPU ID of where to send IPIs */ - char IPI_owner[8]; /* IPI owner's name */ + int notify_IRQ_nasid; /* nasid of where to send notify IRQs */ + int notify_IRQ_phys_cpuid; /* CPUID of where to send notify IRQs */ + char notify_IRQ_owner[8]; /* notify IRQ's owner's name */ - AMO_t *remote_IPI_amo_va; /* address of remote IPI AMO_t structure */ - AMO_t *local_IPI_amo_va; /* address of IPI AMO_t structure */ + AMO_t *remote_chctl_amo_va; /* address of remote chctl flags' AMO_t */ + AMO_t *local_chctl_amo_va; /* address of chctl flags' AMO_t */ struct timer_list dropped_notify_IRQ_timer; /* dropped IRQ timer */ }; @@ -536,7 +585,10 @@ struct xpc_partition { atomic_t nchannels_engaged; /* #of channels engaged with remote part */ struct xpc_channel *channels; /* array of channel structures */ - /* fields used to pass args when opening or closing a channel */ + /* fields used for managing channel avialability and activity */ + + union xpc_channel_ctl_flags chctl; /* chctl flags yet to be processed */ + spinlock_t chctl_lock; /* chctl flags lock */ void *local_openclose_args_base; /* base address of kmalloc'd space */ struct xpc_openclose_args *local_openclose_args; /* local's args */ @@ -544,11 +596,6 @@ struct xpc_partition { struct xpc_openclose_args *remote_openclose_args; /* copy of remote's */ /* args */ - /* IPI sending, receiving and handling related fields */ - - u64 local_IPI_amo; /* IPI amo flags yet to be handled */ - spinlock_t IPI_lock; /* IPI handler lock */ - /* channel manager related fields */ atomic_t channel_mgr_requests; /* #of requests to activate chan mgr */ @@ -580,11 +627,12 @@ struct xpc_partition { #define XPC_P_TORNDOWN 0x03 /* infrastructure is torndown */ /* - * struct xpc_partition IPI_timer #of seconds to wait before checking for - * dropped IPIs. These occur whenever an IPI amo write doesn't complete until - * after the IPI was received. + * struct xpc_partition_sn2's dropped notify IRQ timer is set to wait the + * following interval #of seconds before checking for dropped notify IRQs. + * These can occur whenever an IRQ's associated amo write doesn't complete + * until after the IRQ was received. */ -#define XPC_P_DROPPED_IPI_WAIT_INTERVAL (0.25 * HZ) +#define XPC_DROPPED_NOTIFY_IRQ_WAIT_INTERVAL (0.25 * HZ) /* number of seconds to wait for other partitions to disengage */ #define XPC_DISENGAGE_DEFAULT_TIMELIMIT 90 @@ -617,9 +665,9 @@ extern void (*xpc_offline_heartbeat) (void); extern void (*xpc_online_heartbeat) (void); extern void (*xpc_check_remote_hb) (void); extern enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *); -extern u64 (*xpc_get_IPI_flags) (struct xpc_partition *); +extern u64 (*xpc_get_chctl_all_flags) (struct xpc_partition *); extern void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *); -extern void (*xpc_process_msg_IPI) (struct xpc_partition *, int); +extern void (*xpc_process_msg_chctl_flags) (struct xpc_partition *, int); extern int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *); extern struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *); extern void (*xpc_request_partition_activation) (struct xpc_rsvd_page *, u64, @@ -638,14 +686,13 @@ extern int (*xpc_any_partition_engaged) (void); extern void (*xpc_indicate_partition_disengaged) (struct xpc_partition *); extern void (*xpc_assume_partition_disengaged) (short); -extern void (*xpc_send_channel_closerequest) (struct xpc_channel *, - unsigned long *); -extern void (*xpc_send_channel_closereply) (struct xpc_channel *, +extern void (*xpc_send_chctl_closerequest) (struct xpc_channel *, unsigned long *); -extern void (*xpc_send_channel_openrequest) (struct xpc_channel *, - unsigned long *); -extern void (*xpc_send_channel_openreply) (struct xpc_channel *, +extern void (*xpc_send_chctl_closereply) (struct xpc_channel *, + unsigned long *); +extern void (*xpc_send_chctl_openrequest) (struct xpc_channel *, unsigned long *); +extern void (*xpc_send_chctl_openreply) (struct xpc_channel *, unsigned long *); extern enum xp_retval (*xpc_send_msg) (struct xpc_channel *, u32, void *, u16, u8, xpc_notify_func, void *); @@ -689,7 +736,7 @@ extern enum xp_retval xpc_initiate_send(short, int, u32, void *, u16); extern enum xp_retval xpc_initiate_send_notify(short, int, u32, void *, u16, xpc_notify_func, void *); extern void xpc_initiate_received(short, int, void *); -extern void xpc_process_channel_activity(struct xpc_partition *); +extern void xpc_process_sent_chctl_flags(struct xpc_partition *); extern void xpc_connected_callout(struct xpc_channel *); extern void xpc_deliver_msg(struct xpc_channel *); extern void xpc_disconnect_channel(const int, struct xpc_channel *, @@ -799,25 +846,4 @@ xpc_part_ref(struct xpc_partition *part) (_p)->reason_line = _line; \ } -/* - * The sending and receiving of IPIs includes the setting of an >>>AMO variable - * to indicate the reason the IPI was sent. The 64-bit variable is divided - * up into eight bytes, ordered from right to left. Byte zero pertains to - * channel 0, byte one to channel 1, and so on. Each byte is described by - * the following IPI flags. - */ - -#define XPC_IPI_CLOSEREQUEST 0x01 -#define XPC_IPI_CLOSEREPLY 0x02 -#define XPC_IPI_OPENREQUEST 0x04 -#define XPC_IPI_OPENREPLY 0x08 -#define XPC_IPI_MSGREQUEST 0x10 - -/* given an >>>AMO variable and a channel#, get its associated IPI flags */ -#define XPC_GET_IPI_FLAGS(_amo, _c) ((u8) (((_amo) >> ((_c) * 8)) & 0xff)) -#define XPC_SET_IPI_FLAGS(_amo, _c, _f) (_amo) |= ((u64) (_f) << ((_c) * 8)) - -#define XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(_amo) ((_amo) & 0x0f0f0f0f0f0f0f0fUL) -#define XPC_ANY_MSG_IPI_FLAGS_SET(_amo) ((_amo) & 0x1010101010101010UL) - #endif /* _DRIVERS_MISC_SGIXP_XPC_H */ diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index 48b16136305..0d3c153d1d0 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -201,7 +201,7 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) if (!(ch->flags & XPC_C_OPENREPLY)) { ch->flags |= XPC_C_OPENREPLY; - xpc_send_channel_openreply(ch, irq_flags); + xpc_send_chctl_openreply(ch, irq_flags); } if (!(ch->flags & XPC_C_ROPENREPLY)) @@ -307,7 +307,7 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) if (!(ch->flags & XPC_C_CLOSEREPLY)) { ch->flags |= XPC_C_CLOSEREPLY; - xpc_send_channel_closereply(ch, irq_flags); + xpc_send_chctl_closereply(ch, irq_flags); } if (!(ch->flags & XPC_C_RCLOSEREPLY)) @@ -344,15 +344,15 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) if (ch->flags & XPC_C_WDISCONNECT) { /* we won't lose the CPU since we're holding ch->lock */ complete(&ch->wdisconnect_wait); - } else if (ch->delayed_IPI_flags) { + } else if (ch->delayed_chctl_flags) { if (part->act_state != XPC_P_DEACTIVATING) { - /* time to take action on any delayed IPI flags */ - spin_lock(&part->IPI_lock); - XPC_SET_IPI_FLAGS(part->local_IPI_amo, ch->number, - ch->delayed_IPI_flags); - spin_unlock(&part->IPI_lock); + /* time to take action on any delayed chctl flags */ + spin_lock(&part->chctl_lock); + part->chctl.flags[ch->number] |= + ch->delayed_chctl_flags; + spin_unlock(&part->chctl_lock); } - ch->delayed_IPI_flags = 0; + ch->delayed_chctl_flags = 0; } } @@ -360,8 +360,8 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) * Process a change in the channel's remote connection state. */ static void -xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, - u8 IPI_flags) +xpc_process_openclose_chctl_flags(struct xpc_partition *part, int ch_number, + u8 chctl_flags) { unsigned long irq_flags; struct xpc_openclose_args *args = @@ -376,24 +376,24 @@ again: if ((ch->flags & XPC_C_DISCONNECTED) && (ch->flags & XPC_C_WDISCONNECT)) { /* - * Delay processing IPI flags until thread waiting disconnect + * Delay processing chctl flags until thread waiting disconnect * has had a chance to see that the channel is disconnected. */ - ch->delayed_IPI_flags |= IPI_flags; + ch->delayed_chctl_flags |= chctl_flags; spin_unlock_irqrestore(&ch->lock, irq_flags); return; } - if (IPI_flags & XPC_IPI_CLOSEREQUEST) { + if (chctl_flags & XPC_CHCTL_CLOSEREQUEST) { - dev_dbg(xpc_chan, "XPC_IPI_CLOSEREQUEST (reason=%d) received " + dev_dbg(xpc_chan, "XPC_CHCTL_CLOSEREQUEST (reason=%d) received " "from partid=%d, channel=%d\n", args->reason, ch->partid, ch->number); /* * If RCLOSEREQUEST is set, we're probably waiting for * RCLOSEREPLY. We should find it and a ROPENREQUEST packed - * with this RCLOSEREQUEST in the IPI_flags. + * with this RCLOSEREQUEST in the chctl_flags. */ if (ch->flags & XPC_C_RCLOSEREQUEST) { @@ -402,8 +402,8 @@ again: DBUG_ON(!(ch->flags & XPC_C_CLOSEREPLY)); DBUG_ON(ch->flags & XPC_C_RCLOSEREPLY); - DBUG_ON(!(IPI_flags & XPC_IPI_CLOSEREPLY)); - IPI_flags &= ~XPC_IPI_CLOSEREPLY; + DBUG_ON(!(chctl_flags & XPC_CHCTL_CLOSEREPLY)); + chctl_flags &= ~XPC_CHCTL_CLOSEREPLY; ch->flags |= XPC_C_RCLOSEREPLY; /* both sides have finished disconnecting */ @@ -413,17 +413,15 @@ again: } if (ch->flags & XPC_C_DISCONNECTED) { - if (!(IPI_flags & XPC_IPI_OPENREQUEST)) { - if ((XPC_GET_IPI_FLAGS(part->local_IPI_amo, - ch_number) & - XPC_IPI_OPENREQUEST)) { - - DBUG_ON(ch->delayed_IPI_flags != 0); - spin_lock(&part->IPI_lock); - XPC_SET_IPI_FLAGS(part->local_IPI_amo, - ch_number, - XPC_IPI_CLOSEREQUEST); - spin_unlock(&part->IPI_lock); + if (!(chctl_flags & XPC_CHCTL_OPENREQUEST)) { + if (part->chctl.flags[ch_number] & + XPC_CHCTL_OPENREQUEST) { + + DBUG_ON(ch->delayed_chctl_flags != 0); + spin_lock(&part->chctl_lock); + part->chctl.flags[ch_number] |= + XPC_CHCTL_CLOSEREQUEST; + spin_unlock(&part->chctl_lock); } spin_unlock_irqrestore(&ch->lock, irq_flags); return; @@ -436,7 +434,7 @@ again: ch->flags |= (XPC_C_CONNECTING | XPC_C_ROPENREQUEST); } - IPI_flags &= ~(XPC_IPI_OPENREQUEST | XPC_IPI_OPENREPLY); + chctl_flags &= ~(XPC_CHCTL_OPENREQUEST | XPC_CHCTL_OPENREPLY); /* * The meaningful CLOSEREQUEST connection state fields are: @@ -454,7 +452,7 @@ again: XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags); - DBUG_ON(IPI_flags & XPC_IPI_CLOSEREPLY); + DBUG_ON(chctl_flags & XPC_CHCTL_CLOSEREPLY); spin_unlock_irqrestore(&ch->lock, irq_flags); return; } @@ -462,10 +460,10 @@ again: xpc_process_disconnect(ch, &irq_flags); } - if (IPI_flags & XPC_IPI_CLOSEREPLY) { + if (chctl_flags & XPC_CHCTL_CLOSEREPLY) { - dev_dbg(xpc_chan, "XPC_IPI_CLOSEREPLY received from partid=%d," - " channel=%d\n", ch->partid, ch->number); + dev_dbg(xpc_chan, "XPC_CHCTL_CLOSEREPLY received from partid=" + "%d, channel=%d\n", ch->partid, ch->number); if (ch->flags & XPC_C_DISCONNECTED) { DBUG_ON(part->act_state != XPC_P_DEACTIVATING); @@ -476,15 +474,14 @@ again: DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST)); if (!(ch->flags & XPC_C_RCLOSEREQUEST)) { - if ((XPC_GET_IPI_FLAGS(part->local_IPI_amo, ch_number) - & XPC_IPI_CLOSEREQUEST)) { - - DBUG_ON(ch->delayed_IPI_flags != 0); - spin_lock(&part->IPI_lock); - XPC_SET_IPI_FLAGS(part->local_IPI_amo, - ch_number, - XPC_IPI_CLOSEREPLY); - spin_unlock(&part->IPI_lock); + if (part->chctl.flags[ch_number] & + XPC_CHCTL_CLOSEREQUEST) { + + DBUG_ON(ch->delayed_chctl_flags != 0); + spin_lock(&part->chctl_lock); + part->chctl.flags[ch_number] |= + XPC_CHCTL_CLOSEREPLY; + spin_unlock(&part->chctl_lock); } spin_unlock_irqrestore(&ch->lock, irq_flags); return; @@ -498,9 +495,9 @@ again: } } - if (IPI_flags & XPC_IPI_OPENREQUEST) { + if (chctl_flags & XPC_CHCTL_OPENREQUEST) { - dev_dbg(xpc_chan, "XPC_IPI_OPENREQUEST (msg_size=%d, " + dev_dbg(xpc_chan, "XPC_CHCTL_OPENREQUEST (msg_size=%d, " "local_nentries=%d) received from partid=%d, " "channel=%d\n", args->msg_size, args->local_nentries, ch->partid, ch->number); @@ -512,7 +509,7 @@ again: } if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_WDISCONNECT)) { - ch->delayed_IPI_flags |= XPC_IPI_OPENREQUEST; + ch->delayed_chctl_flags |= XPC_CHCTL_OPENREQUEST; spin_unlock_irqrestore(&ch->lock, irq_flags); return; } @@ -554,13 +551,13 @@ again: xpc_process_connect(ch, &irq_flags); } - if (IPI_flags & XPC_IPI_OPENREPLY) { + if (chctl_flags & XPC_CHCTL_OPENREPLY) { - dev_dbg(xpc_chan, "XPC_IPI_OPENREPLY (local_msgqueue_pa=0x%lx, " - "local_nentries=%d, remote_nentries=%d) received from " - "partid=%d, channel=%d\n", args->local_msgqueue_pa, - args->local_nentries, args->remote_nentries, - ch->partid, ch->number); + dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY (local_msgqueue_pa=" + "0x%lx, local_nentries=%d, remote_nentries=%d) " + "received from partid=%d, channel=%d\n", + args->local_msgqueue_pa, args->local_nentries, + args->remote_nentries, ch->partid, ch->number); if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED)) { spin_unlock_irqrestore(&ch->lock, irq_flags); @@ -591,7 +588,7 @@ again: ch->remote_msgqueue_pa = args->local_msgqueue_pa; if (args->local_nentries < ch->remote_nentries) { - dev_dbg(xpc_chan, "XPC_IPI_OPENREPLY: new " + dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY: new " "remote_nentries=%d, old remote_nentries=%d, " "partid=%d, channel=%d\n", args->local_nentries, ch->remote_nentries, @@ -600,7 +597,7 @@ again: ch->remote_nentries = args->local_nentries; } if (args->remote_nentries < ch->local_nentries) { - dev_dbg(xpc_chan, "XPC_IPI_OPENREPLY: new " + dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY: new " "local_nentries=%d, old local_nentries=%d, " "partid=%d, channel=%d\n", args->remote_nentries, ch->local_nentries, @@ -690,7 +687,7 @@ xpc_connect_channel(struct xpc_channel *ch) /* initiate the connection */ ch->flags |= (XPC_C_OPENREQUEST | XPC_C_CONNECTING); - xpc_send_channel_openrequest(ch, &irq_flags); + xpc_send_chctl_openrequest(ch, &irq_flags); xpc_process_connect(ch, &irq_flags); @@ -700,15 +697,15 @@ xpc_connect_channel(struct xpc_channel *ch) } void -xpc_process_channel_activity(struct xpc_partition *part) +xpc_process_sent_chctl_flags(struct xpc_partition *part) { unsigned long irq_flags; - u64 IPI_amo, IPI_flags; + union xpc_channel_ctl_flags chctl; struct xpc_channel *ch; int ch_number; u32 ch_flags; - IPI_amo = xpc_get_IPI_flags(part); + chctl.all_flags = xpc_get_chctl_all_flags(part); /* * Initiate channel connections for registered channels. @@ -721,14 +718,14 @@ xpc_process_channel_activity(struct xpc_partition *part) ch = &part->channels[ch_number]; /* - * Process any open or close related IPI flags, and then deal + * Process any open or close related chctl flags, and then deal * with connecting or disconnecting the channel as required. */ - IPI_flags = XPC_GET_IPI_FLAGS(IPI_amo, ch_number); - - if (XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(IPI_flags)) - xpc_process_openclose_IPI(part, ch_number, IPI_flags); + if (chctl.flags[ch_number] & XPC_OPENCLOSE_CHCTL_FLAGS) { + xpc_process_openclose_chctl_flags(part, ch_number, + chctl.flags[ch_number]); + } ch_flags = ch->flags; /* need an atomic snapshot of flags */ @@ -755,13 +752,13 @@ xpc_process_channel_activity(struct xpc_partition *part) } /* - * Process any message related IPI flags, this may involve the - * activation of kthreads to deliver any pending messages sent - * from the other partition. + * Process any message related chctl flags, this may involve + * the activation of kthreads to deliver any pending messages + * sent from the other partition. */ - if (XPC_ANY_MSG_IPI_FLAGS_SET(IPI_flags)) - xpc_process_msg_IPI(part, ch_number); + if (chctl.flags[ch_number] & XPC_MSG_CHCTL_FLAGS) + xpc_process_msg_chctl_flags(part, ch_number); } } @@ -937,7 +934,7 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch, XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY | XPC_C_CONNECTING | XPC_C_CONNECTED); - xpc_send_channel_closerequest(ch, irq_flags); + xpc_send_chctl_closerequest(ch, irq_flags); if (channel_was_connected) ch->flags |= XPC_C_WASCONNECTED; diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index 563aaf4a2ff..43f5b686ecf 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -25,18 +25,18 @@ * * Caveats: * - * . We currently have no way to determine which nasid an IPI came - * from. Thus, >>> xpc_IPI_send() does a remote AMO write followed by - * an IPI. The AMO indicates where data is to be pulled from, so - * after the IPI arrives, the remote partition checks the AMO word. - * The IPI can actually arrive before the AMO however, so other code - * must periodically check for this case. Also, remote AMO operations - * do not reliably time out. Thus we do a remote PIO read solely to - * know whether the remote partition is down and whether we should - * stop sending IPIs to it. This remote PIO read operation is set up - * in a special nofault region so SAL knows to ignore (and cleanup) - * any errors due to the remote AMO write, PIO read, and/or PIO - * write operations. + * . Currently on sn2, we have no way to determine which nasid an IRQ + * came from. Thus, xpc_send_IRQ_sn2() does a remote AMO write + * followed by an IPI. The AMO indicates where data is to be pulled + * from, so after the IPI arrives, the remote partition checks the AMO + * word. The IPI can actually arrive before the AMO however, so other + * code must periodically check for this case. Also, remote AMO + * operations do not reliably time out. Thus we do a remote PIO read + * solely to know whether the remote partition is down and whether we + * should stop sending IPIs to it. This remote PIO read operation is + * set up in a special nofault region so SAL knows to ignore (and + * cleanup) any errors due to the remote AMO write, PIO read, and/or + * PIO write operations. * * If/when new hardware solves this IPI problem, we should abandon * the current approach. @@ -185,8 +185,8 @@ void (*xpc_check_remote_hb) (void); enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *part); void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *ch); -u64 (*xpc_get_IPI_flags) (struct xpc_partition *part); -void (*xpc_process_msg_IPI) (struct xpc_partition *part, int ch_number); +u64 (*xpc_get_chctl_all_flags) (struct xpc_partition *part); +void (*xpc_process_msg_chctl_flags) (struct xpc_partition *part, int ch_number); int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *ch); struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *ch); @@ -206,14 +206,14 @@ int (*xpc_any_partition_engaged) (void); void (*xpc_indicate_partition_disengaged) (struct xpc_partition *part); void (*xpc_assume_partition_disengaged) (short partid); -void (*xpc_send_channel_closerequest) (struct xpc_channel *ch, - unsigned long *irq_flags); -void (*xpc_send_channel_closereply) (struct xpc_channel *ch, +void (*xpc_send_chctl_closerequest) (struct xpc_channel *ch, unsigned long *irq_flags); -void (*xpc_send_channel_openrequest) (struct xpc_channel *ch, - unsigned long *irq_flags); -void (*xpc_send_channel_openreply) (struct xpc_channel *ch, +void (*xpc_send_chctl_closereply) (struct xpc_channel *ch, + unsigned long *irq_flags); +void (*xpc_send_chctl_openrequest) (struct xpc_channel *ch, unsigned long *irq_flags); +void (*xpc_send_chctl_openreply) (struct xpc_channel *ch, + unsigned long *irq_flags); enum xp_retval (*xpc_send_msg) (struct xpc_channel *ch, u32 flags, void *payload, u16 payload_size, u8 notify_type, @@ -302,7 +302,7 @@ xpc_hb_checker(void *ignore) /* * We need to periodically recheck to ensure no - * IPI/AMO pairs have been missed. That check + * IRQ/AMO pairs have been missed. That check * must always reset xpc_hb_check_timeout. */ force_IRQ = 1; @@ -378,7 +378,7 @@ xpc_channel_mgr(struct xpc_partition *part) atomic_read(&part->nchannels_active) > 0 || !xpc_partition_disengaged(part)) { - xpc_process_channel_activity(part); + xpc_process_sent_chctl_flags(part); /* * Wait until we've been requested to activate kthreads or @@ -396,7 +396,7 @@ xpc_channel_mgr(struct xpc_partition *part) atomic_dec(&part->channel_mgr_requests); (void)wait_event_interruptible(part->channel_mgr_wq, (atomic_read(&part->channel_mgr_requests) > 0 || - part->local_IPI_amo != 0 || + part->chctl.all_flags != 0 || (part->act_state == XPC_P_DEACTIVATING && atomic_read(&part->nchannels_active) == 0 && xpc_partition_disengaged(part)))); @@ -753,16 +753,15 @@ xpc_disconnect_wait(int ch_number) DBUG_ON(!(ch->flags & XPC_C_DISCONNECTED)); wakeup_channel_mgr = 0; - if (ch->delayed_IPI_flags) { + if (ch->delayed_chctl_flags) { if (part->act_state != XPC_P_DEACTIVATING) { - spin_lock(&part->IPI_lock); - XPC_SET_IPI_FLAGS(part->local_IPI_amo, - ch->number, - ch->delayed_IPI_flags); - spin_unlock(&part->IPI_lock); + spin_lock(&part->chctl_lock); + part->chctl.flags[ch->number] |= + ch->delayed_chctl_flags; + spin_unlock(&part->chctl_lock); wakeup_channel_mgr = 1; } - ch->delayed_IPI_flags = 0; + ch->delayed_chctl_flags = 0; } ch->flags &= ~XPC_C_WDISCONNECT; diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index 69d74bd5689..0fef7d86a5a 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -104,20 +104,20 @@ xpc_disallow_IPI_ops_sn2(void) } /* - * The following set of macros and functions are used for the sending and - * receiving of IPIs (also known as IRQs). There are two flavors of IPIs, - * one that is associated with partition activity (SGI_XPC_ACTIVATE) and - * the other that is associated with channel activity (SGI_XPC_NOTIFY). + * The following set of functions are used for the sending and receiving of + * IRQs (also known as IPIs). There are two flavors of IRQs, one that is + * associated with partition activity (SGI_XPC_ACTIVATE) and the other that + * is associated with channel activity (SGI_XPC_NOTIFY). */ static u64 -xpc_IPI_receive_sn2(AMO_t *amo) +xpc_receive_IRQ_amo_sn2(AMO_t *amo) { return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_CLEAR); } static enum xp_retval -xpc_IPI_send_sn2(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector) +xpc_send_IRQ_sn2(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector) { int ret = 0; unsigned long irq_flags; @@ -131,7 +131,7 @@ xpc_IPI_send_sn2(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector) * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we * didn't, we'd never know that the other partition is down and would - * keep sending IPIs and AMOs to it until the heartbeat times out. + * keep sending IRQs and AMOs to it until the heartbeat times out. */ ret = xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->variable), xp_nofault_PIOR_target)); @@ -142,16 +142,16 @@ xpc_IPI_send_sn2(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector) } static AMO_t * -xpc_IPI_init_sn2(int index) +xpc_init_IRQ_amo_sn2(int index) { AMO_t *amo = xpc_vars->amos_page + index; - (void)xpc_IPI_receive_sn2(amo); /* clear AMO variable */ + (void)xpc_receive_IRQ_amo_sn2(amo); /* clear AMO variable */ return amo; } /* - * IPIs associated with SGI_XPC_ACTIVATE IRQ. + * Functions associated with SGI_XPC_ACTIVATE IRQ. */ /* @@ -166,23 +166,23 @@ xpc_handle_activate_IRQ_sn2(int irq, void *dev_id) } /* - * Flag the appropriate AMO variable and send an IPI to the specified node. + * Flag the appropriate AMO variable and send an IRQ to the specified node. */ static void -xpc_activate_IRQ_send_sn2(u64 amos_page_pa, int from_nasid, int to_nasid, - int to_phys_cpuid) +xpc_send_activate_IRQ_sn2(u64 amos_page_pa, int from_nasid, int to_nasid, + int to_phys_cpuid) { int w_index = XPC_NASID_W_INDEX(from_nasid); int b_index = XPC_NASID_B_INDEX(from_nasid); AMO_t *amos = (AMO_t *)__va(amos_page_pa + (XPC_ACTIVATE_IRQ_AMOS * sizeof(AMO_t))); - (void)xpc_IPI_send_sn2(&amos[w_index], (1UL << b_index), to_nasid, + (void)xpc_send_IRQ_sn2(&amos[w_index], (1UL << b_index), to_nasid, to_phys_cpuid, SGI_XPC_ACTIVATE); } static void -xpc_activate_IRQ_send_local_sn2(int from_nasid) +xpc_send_local_activate_IRQ_sn2(int from_nasid) { int w_index = XPC_NASID_W_INDEX(from_nasid); int b_index = XPC_NASID_B_INDEX(from_nasid); @@ -197,29 +197,29 @@ xpc_activate_IRQ_send_local_sn2(int from_nasid) } /* - * IPIs associated with SGI_XPC_NOTIFY IRQ. + * Functions associated with SGI_XPC_NOTIFY IRQ. */ /* - * Check to see if there is any channel activity to/from the specified - * partition. + * Check to see if any chctl flags were sent from the specified partition. */ static void -xpc_check_for_channel_activity_sn2(struct xpc_partition *part) +xpc_check_for_sent_chctl_flags_sn2(struct xpc_partition *part) { - u64 IPI_amo; + union xpc_channel_ctl_flags chctl; unsigned long irq_flags; - IPI_amo = xpc_IPI_receive_sn2(part->sn.sn2.local_IPI_amo_va); - if (IPI_amo == 0) + chctl.all_flags = xpc_receive_IRQ_amo_sn2(part->sn.sn2. + local_chctl_amo_va); + if (chctl.all_flags == 0) return; - spin_lock_irqsave(&part->IPI_lock, irq_flags); - part->local_IPI_amo |= IPI_amo; - spin_unlock_irqrestore(&part->IPI_lock, irq_flags); + spin_lock_irqsave(&part->chctl_lock, irq_flags); + part->chctl.all_flags |= chctl.all_flags; + spin_unlock_irqrestore(&part->chctl_lock, irq_flags); - dev_dbg(xpc_chan, "received IPI from partid=%d, IPI_amo=0x%lx\n", - XPC_PARTID(part), IPI_amo); + dev_dbg(xpc_chan, "received notify IRQ from partid=%d, chctl.all_flags=" + "0x%lx\n", XPC_PARTID(part), chctl.all_flags); xpc_wakeup_channel_mgr(part); } @@ -228,17 +228,17 @@ xpc_check_for_channel_activity_sn2(struct xpc_partition *part) * Handle the receipt of a SGI_XPC_NOTIFY IRQ by seeing whether the specified * partition actually sent it. Since SGI_XPC_NOTIFY IRQs may be shared by more * than one partition, we use an AMO_t structure per partition to indicate - * whether a partition has sent an IPI or not. If it has, then wake up the + * whether a partition has sent an IRQ or not. If it has, then wake up the * associated kthread to handle it. * - * All SGI_XPC_NOTIFY IRQs received by XPC are the result of IPIs sent by XPC + * All SGI_XPC_NOTIFY IRQs received by XPC are the result of IRQs sent by XPC * running on other partitions. * * Noteworthy Arguments: * * irq - Interrupt ReQuest number. NOT USED. * - * dev_id - partid of IPI's potential sender. + * dev_id - partid of IRQ's potential sender. */ static irqreturn_t xpc_handle_notify_IRQ_sn2(int irq, void *dev_id) @@ -249,7 +249,7 @@ xpc_handle_notify_IRQ_sn2(int irq, void *dev_id) DBUG_ON(partid < 0 || partid >= xp_max_npartitions); if (xpc_part_ref(part)) { - xpc_check_for_channel_activity_sn2(part); + xpc_check_for_sent_chctl_flags_sn2(part); xpc_part_deref(part); } @@ -257,45 +257,47 @@ xpc_handle_notify_IRQ_sn2(int irq, void *dev_id) } /* - * Check to see if xpc_handle_notify_IRQ_sn2() dropped any IPIs on the floor - * because the write to their associated IPI amo completed after the IRQ/IPI + * Check to see if xpc_handle_notify_IRQ_sn2() dropped any IRQs on the floor + * because the write to their associated amo variable completed after the IRQ * was received. */ static void -xpc_dropped_notify_IRQ_check_sn2(struct xpc_partition *part) +xpc_check_for_dropped_notify_IRQ_sn2(struct xpc_partition *part) { struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; if (xpc_part_ref(part)) { - xpc_check_for_channel_activity_sn2(part); + xpc_check_for_sent_chctl_flags_sn2(part); part_sn2->dropped_notify_IRQ_timer.expires = jiffies + - XPC_P_DROPPED_IPI_WAIT_INTERVAL; + XPC_DROPPED_NOTIFY_IRQ_WAIT_INTERVAL; add_timer(&part_sn2->dropped_notify_IRQ_timer); xpc_part_deref(part); } } /* - * Send an IPI to the remote partition that is associated with the + * Send a notify IRQ to the remote partition that is associated with the * specified channel. */ static void -xpc_notify_IRQ_send_sn2(struct xpc_channel *ch, u8 ipi_flag, - char *ipi_flag_string, unsigned long *irq_flags) +xpc_send_notify_IRQ_sn2(struct xpc_channel *ch, u8 chctl_flag, + char *chctl_flag_string, unsigned long *irq_flags) { struct xpc_partition *part = &xpc_partitions[ch->partid]; struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; + union xpc_channel_ctl_flags chctl = { 0 }; enum xp_retval ret; if (likely(part->act_state != XPC_P_DEACTIVATING)) { - ret = xpc_IPI_send_sn2(part_sn2->remote_IPI_amo_va, - (u64)ipi_flag << (ch->number * 8), - part_sn2->remote_IPI_nasid, - part_sn2->remote_IPI_phys_cpuid, + chctl.flags[ch->number] = chctl_flag; + ret = xpc_send_IRQ_sn2(part_sn2->remote_chctl_amo_va, + chctl.all_flags, + part_sn2->notify_IRQ_nasid, + part_sn2->notify_IRQ_phys_cpuid, SGI_XPC_NOTIFY); dev_dbg(xpc_chan, "%s sent to partid=%d, channel=%d, ret=%d\n", - ipi_flag_string, ch->partid, ch->number, ret); + chctl_flag_string, ch->partid, ch->number, ret); if (unlikely(ret != xpSuccess)) { if (irq_flags != NULL) spin_unlock_irqrestore(&ch->lock, *irq_flags); @@ -306,78 +308,78 @@ xpc_notify_IRQ_send_sn2(struct xpc_channel *ch, u8 ipi_flag, } } -#define XPC_NOTIFY_IRQ_SEND_SN2(_ch, _ipi_f, _irq_f) \ - xpc_notify_IRQ_send_sn2(_ch, _ipi_f, #_ipi_f, _irq_f) +#define XPC_SEND_NOTIFY_IRQ_SN2(_ch, _ipi_f, _irq_f) \ + xpc_send_notify_IRQ_sn2(_ch, _ipi_f, #_ipi_f, _irq_f) /* * Make it look like the remote partition, which is associated with the - * specified channel, sent us an IPI. This faked IPI will be handled - * by xpc_dropped_notify_IRQ_check_sn2(). + * specified channel, sent us a notify IRQ. This faked IRQ will be handled + * by xpc_check_for_dropped_notify_IRQ_sn2(). */ static void -xpc_notify_IRQ_send_local_sn2(struct xpc_channel *ch, u8 ipi_flag, - char *ipi_flag_string) +xpc_send_local_notify_IRQ_sn2(struct xpc_channel *ch, u8 chctl_flag, + char *chctl_flag_string) { struct xpc_partition *part = &xpc_partitions[ch->partid]; + union xpc_channel_ctl_flags chctl = { 0 }; - FETCHOP_STORE_OP(TO_AMO((u64)&part->sn.sn2.local_IPI_amo_va->variable), - FETCHOP_OR, ((u64)ipi_flag << (ch->number * 8))); + chctl.flags[ch->number] = chctl_flag; + FETCHOP_STORE_OP(TO_AMO((u64)&part->sn.sn2.local_chctl_amo_va-> + variable), FETCHOP_OR, chctl.all_flags); dev_dbg(xpc_chan, "%s sent local from partid=%d, channel=%d\n", - ipi_flag_string, ch->partid, ch->number); + chctl_flag_string, ch->partid, ch->number); } -#define XPC_NOTIFY_IRQ_SEND_LOCAL_SN2(_ch, _ipi_f) \ - xpc_notify_IRQ_send_local_sn2(_ch, _ipi_f, #_ipi_f) +#define XPC_SEND_LOCAL_NOTIFY_IRQ_SN2(_ch, _ipi_f) \ + xpc_send_local_notify_IRQ_sn2(_ch, _ipi_f, #_ipi_f) static void -xpc_send_channel_closerequest_sn2(struct xpc_channel *ch, - unsigned long *irq_flags) +xpc_send_chctl_closerequest_sn2(struct xpc_channel *ch, + unsigned long *irq_flags) { struct xpc_openclose_args *args = ch->local_openclose_args; args->reason = ch->reason; - XPC_NOTIFY_IRQ_SEND_SN2(ch, XPC_IPI_CLOSEREQUEST, irq_flags); + XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_CLOSEREQUEST, irq_flags); } static void -xpc_send_channel_closereply_sn2(struct xpc_channel *ch, - unsigned long *irq_flags) +xpc_send_chctl_closereply_sn2(struct xpc_channel *ch, unsigned long *irq_flags) { - XPC_NOTIFY_IRQ_SEND_SN2(ch, XPC_IPI_CLOSEREPLY, irq_flags); + XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_CLOSEREPLY, irq_flags); } static void -xpc_send_channel_openrequest_sn2(struct xpc_channel *ch, - unsigned long *irq_flags) +xpc_send_chctl_openrequest_sn2(struct xpc_channel *ch, unsigned long *irq_flags) { struct xpc_openclose_args *args = ch->local_openclose_args; args->msg_size = ch->msg_size; args->local_nentries = ch->local_nentries; - XPC_NOTIFY_IRQ_SEND_SN2(ch, XPC_IPI_OPENREQUEST, irq_flags); + XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_OPENREQUEST, irq_flags); } static void -xpc_send_channel_openreply_sn2(struct xpc_channel *ch, unsigned long *irq_flags) +xpc_send_chctl_openreply_sn2(struct xpc_channel *ch, unsigned long *irq_flags) { struct xpc_openclose_args *args = ch->local_openclose_args; args->remote_nentries = ch->remote_nentries; args->local_nentries = ch->local_nentries; args->local_msgqueue_pa = __pa(ch->local_msgqueue); - XPC_NOTIFY_IRQ_SEND_SN2(ch, XPC_IPI_OPENREPLY, irq_flags); + XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_OPENREPLY, irq_flags); } static void -xpc_send_channel_msgrequest_sn2(struct xpc_channel *ch) +xpc_send_chctl_msgrequest_sn2(struct xpc_channel *ch) { - XPC_NOTIFY_IRQ_SEND_SN2(ch, XPC_IPI_MSGREQUEST, NULL); + XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_MSGREQUEST, NULL); } static void -xpc_send_channel_local_msgrequest_sn2(struct xpc_channel *ch) +xpc_send_chctl_local_msgrequest_sn2(struct xpc_channel *ch) { - XPC_NOTIFY_IRQ_SEND_LOCAL_SN2(ch, XPC_IPI_MSGREQUEST); + XPC_SEND_LOCAL_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_MSGREQUEST); } /* @@ -402,7 +404,7 @@ xpc_indicate_partition_engaged_sn2(struct xpc_partition *part) * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we * didn't, we'd never know that the other partition is down and would - * keep sending IPIs and AMOs to it until the heartbeat times out. + * keep sending IRQs and AMOs to it until the heartbeat times out. */ (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> variable), @@ -429,7 +431,7 @@ xpc_indicate_partition_disengaged_sn2(struct xpc_partition *part) * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we * didn't, we'd never know that the other partition is down and would - * keep sending IPIs and AMOs to it until the heartbeat times out. + * keep sending IRQs and AMOs to it until the heartbeat times out. */ (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> variable), @@ -441,7 +443,7 @@ xpc_indicate_partition_disengaged_sn2(struct xpc_partition *part) * Send activate IRQ to get other side to see that we've cleared our * bit in their engaged partitions AMO. */ - xpc_activate_IRQ_send_sn2(part_sn2->remote_amos_page_pa, + xpc_send_activate_IRQ_sn2(part_sn2->remote_amos_page_pa, cnodeid_to_nasid(0), part_sn2->activate_IRQ_nasid, part_sn2->activate_IRQ_phys_cpuid); @@ -595,11 +597,11 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) /* initialize the activate IRQ related AMO variables */ for (i = 0; i < xp_nasid_mask_words; i++) - (void)xpc_IPI_init_sn2(XPC_ACTIVATE_IRQ_AMOS + i); + (void)xpc_init_IRQ_amo_sn2(XPC_ACTIVATE_IRQ_AMOS + i); /* initialize the engaged remote partitions related AMO variables */ - (void)xpc_IPI_init_sn2(XPC_ENGAGED_PARTITIONS_AMO); - (void)xpc_IPI_init_sn2(XPC_DEACTIVATE_REQUEST_AMO); + (void)xpc_init_IRQ_amo_sn2(XPC_ENGAGED_PARTITIONS_AMO); + (void)xpc_init_IRQ_amo_sn2(XPC_DEACTIVATE_REQUEST_AMO); return xpSuccess; } @@ -729,13 +731,13 @@ static void xpc_request_partition_activation_sn2(struct xpc_rsvd_page *remote_rp, u64 remote_rp_pa, int nasid) { - xpc_activate_IRQ_send_local_sn2(nasid); + xpc_send_local_activate_IRQ_sn2(nasid); } static void xpc_request_partition_reactivation_sn2(struct xpc_partition *part) { - xpc_activate_IRQ_send_local_sn2(part->sn.sn2.activate_IRQ_nasid); + xpc_send_local_activate_IRQ_sn2(part->sn.sn2.activate_IRQ_nasid); } static void @@ -755,7 +757,7 @@ xpc_request_partition_deactivation_sn2(struct xpc_partition *part) * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we * didn't, we'd never know that the other partition is down and would - * keep sending IPIs and AMOs to it until the heartbeat times out. + * keep sending IRQs and AMOs to it until the heartbeat times out. */ (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> variable), @@ -767,7 +769,7 @@ xpc_request_partition_deactivation_sn2(struct xpc_partition *part) * Send activate IRQ to get other side to see that we've set our * bit in their deactivate request AMO. */ - xpc_activate_IRQ_send_sn2(part_sn2->remote_amos_page_pa, + xpc_send_activate_IRQ_sn2(part_sn2->remote_amos_page_pa, cnodeid_to_nasid(0), part_sn2->activate_IRQ_nasid, part_sn2->activate_IRQ_phys_cpuid); @@ -789,7 +791,7 @@ xpc_cancel_partition_deactivation_request_sn2(struct xpc_partition *part) * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we * didn't, we'd never know that the other partition is down and would - * keep sending IPIs and AMOs to it until the heartbeat times out. + * keep sending IRQs and AMOs to it until the heartbeat times out. */ (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> variable), @@ -861,11 +863,11 @@ xpc_update_partition_info_sn2(struct xpc_partition *part, u8 remote_rp_version, } /* - * Prior code has determined the nasid which generated an IPI. Inspect - * that nasid to determine if its partition needs to be activated or - * deactivated. + * Prior code has determined the nasid which generated a activate IRQ. + * Inspect that nasid to determine if its partition needs to be activated + * or deactivated. * - * A partition is consider "awaiting activation" if our partition + * A partition is considered "awaiting activation" if our partition * flags indicate it is not active and it has a heartbeat. A * partition is considered "awaiting deactivation" if our partition * flags indicate it is active but it has no heartbeat or it is not @@ -997,7 +999,7 @@ xpc_identify_activate_IRQ_sender_sn2(void) if (xpc_exiting) break; - nasid_mask = xpc_IPI_receive_sn2(&act_amos[word]); + nasid_mask = xpc_receive_IRQ_amo_sn2(&act_amos[word]); if (nasid_mask == 0) { /* no IRQs from nasids in this variable */ continue; @@ -1117,20 +1119,20 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) part_sn2->remote_openclose_args_pa = 0; - part_sn2->local_IPI_amo_va = xpc_IPI_init_sn2(partid); - part->local_IPI_amo = 0; - spin_lock_init(&part->IPI_lock); + part_sn2->local_chctl_amo_va = xpc_init_IRQ_amo_sn2(partid); + part->chctl.all_flags = 0; + spin_lock_init(&part->chctl_lock); - part_sn2->remote_IPI_nasid = 0; - part_sn2->remote_IPI_phys_cpuid = 0; - part_sn2->remote_IPI_amo_va = NULL; + part_sn2->notify_IRQ_nasid = 0; + part_sn2->notify_IRQ_phys_cpuid = 0; + part_sn2->remote_chctl_amo_va = NULL; atomic_set(&part->channel_mgr_requests, 1); init_waitqueue_head(&part->channel_mgr_wq); - sprintf(part_sn2->IPI_owner, "xpc%02d", partid); + sprintf(part_sn2->notify_IRQ_owner, "xpc%02d", partid); ret = request_irq(SGI_XPC_NOTIFY, xpc_handle_notify_IRQ_sn2, - IRQF_SHARED, part_sn2->IPI_owner, + IRQF_SHARED, part_sn2->notify_IRQ_owner, (void *)(u64)partid); if (ret != 0) { dev_err(xpc_chan, "can't register NOTIFY IRQ handler, " @@ -1139,13 +1141,13 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) goto out_5; } - /* Setup a timer to check for dropped IPIs */ + /* Setup a timer to check for dropped notify IRQs */ timer = &part_sn2->dropped_notify_IRQ_timer; init_timer(timer); timer->function = - (void (*)(unsigned long))xpc_dropped_notify_IRQ_check_sn2; + (void (*)(unsigned long))xpc_check_for_dropped_notify_IRQ_sn2; timer->data = (unsigned long)part; - timer->expires = jiffies + XPC_P_DROPPED_IPI_WAIT_INTERVAL; + timer->expires = jiffies + XPC_DROPPED_NOTIFY_IRQ_WAIT_INTERVAL; add_timer(timer); part->nchannels = XPC_MAX_NCHANNELS; @@ -1196,10 +1198,10 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) xpc_vars_part[partid].GPs_pa = __pa(part_sn2->local_GPs); xpc_vars_part[partid].openclose_args_pa = __pa(part->local_openclose_args); - xpc_vars_part[partid].IPI_amo_pa = __pa(part_sn2->local_IPI_amo_va); + xpc_vars_part[partid].chctl_amo_pa = __pa(part_sn2->local_chctl_amo_va); cpuid = raw_smp_processor_id(); /* any CPU in this partition will do */ - xpc_vars_part[partid].IPI_nasid = cpuid_to_nasid(cpuid); - xpc_vars_part[partid].IPI_phys_cpuid = cpu_physical_id(cpuid); + xpc_vars_part[partid].notify_IRQ_nasid = cpuid_to_nasid(cpuid); + xpc_vars_part[partid].notify_IRQ_phys_cpuid = cpu_physical_id(cpuid); xpc_vars_part[partid].nchannels = part->nchannels; xpc_vars_part[partid].magic = XPC_VP_MAGIC1; @@ -1239,7 +1241,7 @@ xpc_teardown_infrastructure_sn2(struct xpc_partition *part) * processes by marking it as no longer setup. Then we make it * inaccessible to remote processes by clearing the XPC per partition * specific variable's magic # (which indicates that these variables - * are no longer valid) and by ignoring all XPC notify IPIs sent to + * are no longer valid) and by ignoring all XPC notify IRQs sent to * this partition. */ @@ -1275,7 +1277,7 @@ xpc_teardown_infrastructure_sn2(struct xpc_partition *part) part_sn2->local_GPs = NULL; kfree(part->channels); part->channels = NULL; - part_sn2->local_IPI_amo_va = NULL; + part_sn2->local_chctl_amo_va = NULL; } /* @@ -1370,7 +1372,7 @@ xpc_pull_remote_vars_part_sn2(struct xpc_partition *part) if (pulled_entry->GPs_pa == 0 || pulled_entry->openclose_args_pa == 0 || - pulled_entry->IPI_amo_pa == 0) { + pulled_entry->chctl_amo_pa == 0) { dev_err(xpc_chan, "partition %d's XPC vars_part for " "partition %d are not valid\n", partid, @@ -1383,10 +1385,11 @@ xpc_pull_remote_vars_part_sn2(struct xpc_partition *part) part_sn2->remote_GPs_pa = pulled_entry->GPs_pa; part_sn2->remote_openclose_args_pa = pulled_entry->openclose_args_pa; - part_sn2->remote_IPI_amo_va = - (AMO_t *)__va(pulled_entry->IPI_amo_pa); - part_sn2->remote_IPI_nasid = pulled_entry->IPI_nasid; - part_sn2->remote_IPI_phys_cpuid = pulled_entry->IPI_phys_cpuid; + part_sn2->remote_chctl_amo_va = + (AMO_t *)__va(pulled_entry->chctl_amo_pa); + part_sn2->notify_IRQ_nasid = pulled_entry->notify_IRQ_nasid; + part_sn2->notify_IRQ_phys_cpuid = + pulled_entry->notify_IRQ_phys_cpuid; if (part->nchannels > pulled_entry->nchannels) part->nchannels = pulled_entry->nchannels; @@ -1437,7 +1440,7 @@ xpc_make_first_contact_sn2(struct xpc_partition *part) * Send activate IRQ to get other side to activate if they've not * already begun to do so. */ - xpc_activate_IRQ_send_sn2(part_sn2->remote_amos_page_pa, + xpc_send_activate_IRQ_sn2(part_sn2->remote_amos_page_pa, cnodeid_to_nasid(0), part_sn2->activate_IRQ_nasid, part_sn2->activate_IRQ_phys_cpuid); @@ -1462,28 +1465,28 @@ xpc_make_first_contact_sn2(struct xpc_partition *part) } /* - * Get the IPI flags and pull the openclose args and/or remote GPs as needed. + * Get the chctl flags and pull the openclose args and/or remote GPs as needed. */ static u64 -xpc_get_IPI_flags_sn2(struct xpc_partition *part) +xpc_get_chctl_all_flags_sn2(struct xpc_partition *part) { struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; unsigned long irq_flags; - u64 IPI_amo; + union xpc_channel_ctl_flags chctl; enum xp_retval ret; /* - * See if there are any IPI flags to be handled. + * See if there are any chctl flags to be handled. */ - spin_lock_irqsave(&part->IPI_lock, irq_flags); - IPI_amo = part->local_IPI_amo; - if (IPI_amo != 0) - part->local_IPI_amo = 0; + spin_lock_irqsave(&part->chctl_lock, irq_flags); + chctl = part->chctl; + if (chctl.all_flags != 0) + part->chctl.all_flags = 0; - spin_unlock_irqrestore(&part->IPI_lock, irq_flags); + spin_unlock_irqrestore(&part->chctl_lock, irq_flags); - if (XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(IPI_amo)) { + if (xpc_any_openclose_chctl_flags_set(&chctl)) { ret = xpc_pull_remote_cachelines_sn2(part, part-> remote_openclose_args, (void *)part_sn2-> @@ -1496,12 +1499,12 @@ xpc_get_IPI_flags_sn2(struct xpc_partition *part) "partition %d, ret=%d\n", XPC_PARTID(part), ret); - /* don't bother processing IPIs anymore */ - IPI_amo = 0; + /* don't bother processing chctl flags anymore */ + chctl.all_flags = 0; } } - if (XPC_ANY_MSG_IPI_FLAGS_SET(IPI_amo)) { + if (xpc_any_msg_chctl_flags_set(&chctl)) { ret = xpc_pull_remote_cachelines_sn2(part, part_sn2->remote_GPs, (void *)part_sn2->remote_GPs_pa, XPC_GP_SIZE); @@ -1511,12 +1514,12 @@ xpc_get_IPI_flags_sn2(struct xpc_partition *part) dev_dbg(xpc_chan, "failed to pull GPs from partition " "%d, ret=%d\n", XPC_PARTID(part), ret); - /* don't bother processing IPIs anymore */ - IPI_amo = 0; + /* don't bother processing chctl flags anymore */ + chctl.all_flags = 0; } } - return IPI_amo; + return chctl.all_flags; } /* @@ -1610,7 +1613,7 @@ xpc_clear_remote_msgqueue_flags_sn2(struct xpc_channel *ch) } static void -xpc_process_msg_IPI_sn2(struct xpc_partition *part, int ch_number) +xpc_process_msg_chctl_flags_sn2(struct xpc_partition *part, int ch_number) { struct xpc_channel *ch = &part->channels[ch_number]; struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; @@ -1827,8 +1830,8 @@ xpc_get_deliverable_msg_sn2(struct xpc_channel *ch) /* * Now we actually send the messages that are ready to be sent by advancing - * the local message queue's Put value and then send an IPI to the recipient - * partition. + * the local message queue's Put value and then send a chctl msgrequest to the + * recipient partition. */ static void xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put) @@ -1836,7 +1839,7 @@ xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put) struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; struct xpc_msg *msg; s64 put = initial_put + 1; - int send_IPI = 0; + int send_msgrequest = 0; while (1) { @@ -1871,7 +1874,7 @@ xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put) dev_dbg(xpc_chan, "local_GP->put changed to %ld, partid=%d, " "channel=%d\n", put, ch->partid, ch->number); - send_IPI = 1; + send_msgrequest = 1; /* * We need to ensure that the message referenced by @@ -1881,8 +1884,8 @@ xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put) initial_put = put; } - if (send_IPI) - xpc_send_channel_msgrequest_sn2(ch); + if (send_msgrequest) + xpc_send_chctl_msgrequest_sn2(ch); } /* @@ -1929,13 +1932,13 @@ xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags, * There aren't any available msg entries at this time. * * In waiting for a message entry to become available, - * we set a timeout in case the other side is not - * sending completion IPIs. This lets us fake an IPI - * that will cause the IPI handler to fetch the latest - * GP values as if an IPI was sent by the other side. + * we set a timeout in case the other side is not sending + * completion interrupts. This lets us fake a notify IRQ + * that will cause the notify IRQ handler to fetch the latest + * GP values as if an interrupt was sent by the other side. */ if (ret == xpTimeout) - xpc_send_channel_local_msgrequest_sn2(ch); + xpc_send_chctl_local_msgrequest_sn2(ch); if (flags & XPC_NOWAIT) return xpNoWait; @@ -1962,8 +1965,8 @@ xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags, /* * Common code that does the actual sending of the message by advancing the - * local message queue's Put value and sends an IPI to the partition the - * message is being sent to. + * local message queue's Put value and sends a chctl msgrequest to the + * partition the message is being sent to. */ static enum xp_retval xpc_send_msg_sn2(struct xpc_channel *ch, u32 flags, void *payload, @@ -2055,7 +2058,7 @@ out_1: /* * Now we actually acknowledge the messages that have been delivered and ack'd * by advancing the cached remote message queue's Get value and if requested - * send an IPI to the message sender's partition. + * send a chctl msgrequest to the message sender's partition. */ static void xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) @@ -2063,7 +2066,7 @@ xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; struct xpc_msg *msg; s64 get = initial_get + 1; - int send_IPI = 0; + int send_msgrequest = 0; while (1) { @@ -2099,7 +2102,7 @@ xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) dev_dbg(xpc_chan, "local_GP->get changed to %ld, partid=%d, " "channel=%d\n", get, ch->partid, ch->number); - send_IPI = (msg_flags & XPC_M_INTERRUPT); + send_msgrequest = (msg_flags & XPC_M_INTERRUPT); /* * We need to ensure that the message referenced by @@ -2109,8 +2112,8 @@ xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) initial_get = get; } - if (send_IPI) - xpc_send_channel_msgrequest_sn2(ch); + if (send_msgrequest) + xpc_send_chctl_msgrequest_sn2(ch); } static void @@ -2168,9 +2171,9 @@ xpc_init_sn2(void) xpc_setup_infrastructure = xpc_setup_infrastructure_sn2; xpc_teardown_infrastructure = xpc_teardown_infrastructure_sn2; xpc_make_first_contact = xpc_make_first_contact_sn2; - xpc_get_IPI_flags = xpc_get_IPI_flags_sn2; + xpc_get_chctl_all_flags = xpc_get_chctl_all_flags_sn2; xpc_notify_senders_of_disconnect = xpc_notify_senders_of_disconnect_sn2; - xpc_process_msg_IPI = xpc_process_msg_IPI_sn2; + xpc_process_msg_chctl_flags = xpc_process_msg_chctl_flags_sn2; xpc_n_of_deliverable_msgs = xpc_n_of_deliverable_msgs_sn2; xpc_get_deliverable_msg = xpc_get_deliverable_msg_sn2; @@ -2181,10 +2184,10 @@ xpc_init_sn2(void) xpc_indicate_partition_disengaged_sn2; xpc_assume_partition_disengaged = xpc_assume_partition_disengaged_sn2; - xpc_send_channel_closerequest = xpc_send_channel_closerequest_sn2; - xpc_send_channel_closereply = xpc_send_channel_closereply_sn2; - xpc_send_channel_openrequest = xpc_send_channel_openrequest_sn2; - xpc_send_channel_openreply = xpc_send_channel_openreply_sn2; + xpc_send_chctl_closerequest = xpc_send_chctl_closerequest_sn2; + xpc_send_chctl_closereply = xpc_send_chctl_closereply_sn2; + xpc_send_chctl_openrequest = xpc_send_chctl_openrequest_sn2; + xpc_send_chctl_openreply = xpc_send_chctl_openreply_sn2; xpc_send_msg = xpc_send_msg_sn2; xpc_received_msg = xpc_received_msg_sn2; diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index c53b229cb04..1401b0f45dc 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c @@ -26,7 +26,7 @@ static DECLARE_BITMAP(xpc_heartbeating_to_mask_uv, XP_MAX_NPARTITIONS_UV); static void *xpc_activate_mq; static void -xpc_IPI_send_local_activate_uv(struct xpc_partition *part) +xpc_send_local_activate_IRQ_uv(struct xpc_partition *part) { /* * >>> make our side think that the remote parition sent an activate @@ -75,13 +75,13 @@ xpc_request_partition_activation_uv(struct xpc_rsvd_page *remote_rp, * >>> part->sn.uv.activate_mq_gpa = remote_rp->sn.activate_mq_gpa; */ - xpc_IPI_send_local_activate_uv(part); + xpc_send_local_activate_IRQ_uv(part); } static void xpc_request_partition_reactivation_uv(struct xpc_partition *part) { - xpc_IPI_send_local_activate_uv(part); + xpc_send_local_activate_IRQ_uv(part); } /* @@ -114,7 +114,7 @@ xpc_make_first_contact_uv(struct xpc_partition *part) } static u64 -xpc_get_IPI_flags_uv(struct xpc_partition *part) +xpc_get_chctl_all_flags_uv(struct xpc_partition *part) { /* >>> this function needs fleshing out */ return 0UL; @@ -140,7 +140,7 @@ xpc_init_uv(void) xpc_setup_infrastructure = xpc_setup_infrastructure_uv; xpc_teardown_infrastructure = xpc_teardown_infrastructure_uv; xpc_make_first_contact = xpc_make_first_contact_uv; - xpc_get_IPI_flags = xpc_get_IPI_flags_uv; + xpc_get_chctl_all_flags = xpc_get_chctl_all_flags_uv; xpc_get_deliverable_msg = xpc_get_deliverable_msg_uv; } -- cgit v1.2.3 From c39838ce21ca8e05857ed7f4be5d289011561905 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:11 -0700 Subject: sgi-xp: replace AMO_t typedef by struct amo Replace the AMO_t typedef by a direct reference to 'struct amo'. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xp_sn2.c | 2 +- drivers/misc/sgi-xp/xpc.h | 24 +++---- drivers/misc/sgi-xp/xpc_main.c | 16 ++--- drivers/misc/sgi-xp/xpc_sn2.c | 139 +++++++++++++++++++++-------------------- 4 files changed, 93 insertions(+), 88 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xp_sn2.c b/drivers/misc/sgi-xp/xp_sn2.c index 3d553fa73f4..1fcfdebca2c 100644 --- a/drivers/misc/sgi-xp/xp_sn2.c +++ b/drivers/misc/sgi-xp/xp_sn2.c @@ -32,7 +32,7 @@ EXPORT_SYMBOL_GPL(xp_nofault_PIOR_target); * If the PIO read times out, the MCA handler will consume the error and * return to a kernel-provided instruction to indicate an error. This PIO read * exists because it is guaranteed to timeout if the destination is down - * (AMO operations do not timeout on at least some CPUs on Shubs <= v1.2, + * (amo operations do not timeout on at least some CPUs on Shubs <= v1.2, * which unfortunately we have to work around). */ static enum xp_retval diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 26a1725f68a..da2680892df 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -38,8 +38,8 @@ /* * The next macros define word or bit representations for given * C-brick nasid in either the SAL provided bit array representing - * nasids in the partition/machine or the AMO_t array used for - * inter-partition initiation communications. + * nasids in the partition/machine or the array of amo structures used + * for inter-partition initiation communications. * * For SN2 machines, C-Bricks are alway even numbered NASIDs. As * such, some space will be saved by insisting that nasid information @@ -144,8 +144,8 @@ struct xpc_vars_sn2 { int activate_IRQ_nasid; int activate_IRQ_phys_cpuid; u64 vars_part_pa; - u64 amos_page_pa; /* paddr of page of AMOs from MSPEC driver */ - AMO_t *amos_page; /* vaddr of page of AMOs from MSPEC driver */ + u64 amos_page_pa; /* paddr of page of amos from MSPEC driver */ + struct amo *amos_page; /* vaddr of page of amos from MSPEC driver */ }; #define XPC_V_VERSION _XPC_VERSION(3, 1) /* version 3.1 of the cross vars */ @@ -153,17 +153,17 @@ struct xpc_vars_sn2 { /* * The following pertains to ia64-sn2 only. * - * Memory for XPC's AMO variables is allocated by the MSPEC driver. These + * Memory for XPC's amo variables is allocated by the MSPEC driver. These * pages are located in the lowest granule. The lowest granule uses 4k pages * for cached references and an alternate TLB handler to never provide a * cacheable mapping for the entire region. This will prevent speculative * reading of cached copies of our lines from being issued which will cause * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64 - * AMO variables (based on XP_MAX_NPARTITIONS_SN2) to identify the senders of - * NOTIFY IRQs, 128 AMO variables (based on XP_NASID_MASK_WORDS) to identify - * the senders of ACTIVATE IRQs, 1 AMO variable to identify which remote + * amo variables (based on XP_MAX_NPARTITIONS_SN2) to identify the senders of + * NOTIFY IRQs, 128 amo variables (based on XP_NASID_MASK_WORDS) to identify + * the senders of ACTIVATE IRQs, 1 amo variable to identify which remote * partitions (i.e., XPCs) consider themselves currently engaged with the - * local XPC and 1 AMO variable to request partition deactivation. + * local XPC and 1 amo variable to request partition deactivation. */ #define XPC_NOTIFY_IRQ_AMOS 0 #define XPC_ACTIVATE_IRQ_AMOS (XPC_NOTIFY_IRQ_AMOS + XP_MAX_NPARTITIONS_SN2) @@ -186,7 +186,7 @@ struct xpc_vars_part_sn2 { u64 openclose_args_pa; /* physical address of open and close args */ u64 GPs_pa; /* physical address of Get/Put values */ - u64 chctl_amo_pa; /* physical address of chctl flags' AMO_t */ + u64 chctl_amo_pa; /* physical address of chctl flags' amo */ int notify_IRQ_nasid; /* nasid of where to send notify IRQs */ int notify_IRQ_phys_cpuid; /* CPUID of where to send notify IRQs */ @@ -547,8 +547,8 @@ struct xpc_partition_sn2 { int notify_IRQ_phys_cpuid; /* CPUID of where to send notify IRQs */ char notify_IRQ_owner[8]; /* notify IRQ's owner's name */ - AMO_t *remote_chctl_amo_va; /* address of remote chctl flags' AMO_t */ - AMO_t *local_chctl_amo_va; /* address of chctl flags' AMO_t */ + struct amo *remote_chctl_amo_va; /* addr of remote chctl flags' amo */ + struct amo *local_chctl_amo_va; /* address of chctl flags' amo */ struct timer_list dropped_notify_IRQ_timer; /* dropped IRQ timer */ }; diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index 43f5b686ecf..2934b447300 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -26,16 +26,16 @@ * Caveats: * * . Currently on sn2, we have no way to determine which nasid an IRQ - * came from. Thus, xpc_send_IRQ_sn2() does a remote AMO write - * followed by an IPI. The AMO indicates where data is to be pulled - * from, so after the IPI arrives, the remote partition checks the AMO - * word. The IPI can actually arrive before the AMO however, so other - * code must periodically check for this case. Also, remote AMO + * came from. Thus, xpc_send_IRQ_sn2() does a remote amo write + * followed by an IPI. The amo indicates where data is to be pulled + * from, so after the IPI arrives, the remote partition checks the amo + * word. The IPI can actually arrive before the amo however, so other + * code must periodically check for this case. Also, remote amo * operations do not reliably time out. Thus we do a remote PIO read * solely to know whether the remote partition is down and whether we * should stop sending IPIs to it. This remote PIO read operation is * set up in a special nofault region so SAL knows to ignore (and - * cleanup) any errors due to the remote AMO write, PIO read, and/or + * cleanup) any errors due to the remote amo write, PIO read, and/or * PIO write operations. * * If/when new hardware solves this IPI problem, we should abandon @@ -302,7 +302,7 @@ xpc_hb_checker(void *ignore) /* * We need to periodically recheck to ensure no - * IRQ/AMO pairs have been missed. That check + * IRQ/amo pairs have been missed. That check * must always reset xpc_hb_check_timeout. */ force_IRQ = 1; @@ -1034,7 +1034,7 @@ xpc_init(void) if (is_shub()) { /* * The ia64-sn2 architecture supports at most 64 partitions. - * And the inability to unregister remote AMOs restricts us + * And the inability to unregister remote amos restricts us * further to only support exactly 64 partitions on this * architecture, no less. */ diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index 0fef7d86a5a..01dd40ec2a8 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -111,13 +111,14 @@ xpc_disallow_IPI_ops_sn2(void) */ static u64 -xpc_receive_IRQ_amo_sn2(AMO_t *amo) +xpc_receive_IRQ_amo_sn2(struct amo *amo) { return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_CLEAR); } static enum xp_retval -xpc_send_IRQ_sn2(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector) +xpc_send_IRQ_sn2(struct amo *amo, u64 flag, int nasid, int phys_cpuid, + int vector) { int ret = 0; unsigned long irq_flags; @@ -131,7 +132,7 @@ xpc_send_IRQ_sn2(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector) * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we * didn't, we'd never know that the other partition is down and would - * keep sending IRQs and AMOs to it until the heartbeat times out. + * keep sending IRQs and amos to it until the heartbeat times out. */ ret = xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->variable), xp_nofault_PIOR_target)); @@ -141,12 +142,12 @@ xpc_send_IRQ_sn2(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector) return ((ret == 0) ? xpSuccess : xpPioReadError); } -static AMO_t * +static struct amo * xpc_init_IRQ_amo_sn2(int index) { - AMO_t *amo = xpc_vars->amos_page + index; + struct amo *amo = xpc_vars->amos_page + index; - (void)xpc_receive_IRQ_amo_sn2(amo); /* clear AMO variable */ + (void)xpc_receive_IRQ_amo_sn2(amo); /* clear amo variable */ return amo; } @@ -166,7 +167,7 @@ xpc_handle_activate_IRQ_sn2(int irq, void *dev_id) } /* - * Flag the appropriate AMO variable and send an IRQ to the specified node. + * Flag the appropriate amo variable and send an IRQ to the specified node. */ static void xpc_send_activate_IRQ_sn2(u64 amos_page_pa, int from_nasid, int to_nasid, @@ -174,8 +175,9 @@ xpc_send_activate_IRQ_sn2(u64 amos_page_pa, int from_nasid, int to_nasid, { int w_index = XPC_NASID_W_INDEX(from_nasid); int b_index = XPC_NASID_B_INDEX(from_nasid); - AMO_t *amos = (AMO_t *)__va(amos_page_pa + - (XPC_ACTIVATE_IRQ_AMOS * sizeof(AMO_t))); + struct amo *amos = (struct amo *)__va(amos_page_pa + + (XPC_ACTIVATE_IRQ_AMOS * + sizeof(struct amo))); (void)xpc_send_IRQ_sn2(&amos[w_index], (1UL << b_index), to_nasid, to_phys_cpuid, SGI_XPC_ACTIVATE); @@ -186,8 +188,9 @@ xpc_send_local_activate_IRQ_sn2(int from_nasid) { int w_index = XPC_NASID_W_INDEX(from_nasid); int b_index = XPC_NASID_B_INDEX(from_nasid); - AMO_t *amos = (AMO_t *)__va(xpc_vars->amos_page_pa + - (XPC_ACTIVATE_IRQ_AMOS * sizeof(AMO_t))); + struct amo *amos = (struct amo *)__va(xpc_vars->amos_page_pa + + (XPC_ACTIVATE_IRQ_AMOS * + sizeof(struct amo))); /* fake the sending and receipt of an activate IRQ from remote nasid */ FETCHOP_STORE_OP(TO_AMO((u64)&amos[w_index].variable), FETCHOP_OR, @@ -227,7 +230,7 @@ xpc_check_for_sent_chctl_flags_sn2(struct xpc_partition *part) /* * Handle the receipt of a SGI_XPC_NOTIFY IRQ by seeing whether the specified * partition actually sent it. Since SGI_XPC_NOTIFY IRQs may be shared by more - * than one partition, we use an AMO_t structure per partition to indicate + * than one partition, we use an amo structure per partition to indicate * whether a partition has sent an IRQ or not. If it has, then wake up the * associated kthread to handle it. * @@ -391,20 +394,20 @@ static void xpc_indicate_partition_engaged_sn2(struct xpc_partition *part) { unsigned long irq_flags; - AMO_t *amo = (AMO_t *)__va(part->sn.sn2.remote_amos_page_pa + - (XPC_ENGAGED_PARTITIONS_AMO * - sizeof(AMO_t))); + struct amo *amo = (struct amo *)__va(part->sn.sn2.remote_amos_page_pa + + (XPC_ENGAGED_PARTITIONS_AMO * + sizeof(struct amo))); local_irq_save(irq_flags); - /* set bit corresponding to our partid in remote partition's AMO */ + /* set bit corresponding to our partid in remote partition's amo */ FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, (1UL << sn_partition_id)); /* * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we * didn't, we'd never know that the other partition is down and would - * keep sending IRQs and AMOs to it until the heartbeat times out. + * keep sending IRQs and amos to it until the heartbeat times out. */ (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> variable), @@ -418,20 +421,20 @@ xpc_indicate_partition_disengaged_sn2(struct xpc_partition *part) { struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; unsigned long irq_flags; - AMO_t *amo = (AMO_t *)__va(part_sn2->remote_amos_page_pa + - (XPC_ENGAGED_PARTITIONS_AMO * - sizeof(AMO_t))); + struct amo *amo = (struct amo *)__va(part_sn2->remote_amos_page_pa + + (XPC_ENGAGED_PARTITIONS_AMO * + sizeof(struct amo))); local_irq_save(irq_flags); - /* clear bit corresponding to our partid in remote partition's AMO */ + /* clear bit corresponding to our partid in remote partition's amo */ FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, ~(1UL << sn_partition_id)); /* * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we * didn't, we'd never know that the other partition is down and would - * keep sending IRQs and AMOs to it until the heartbeat times out. + * keep sending IRQs and amos to it until the heartbeat times out. */ (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> variable), @@ -441,7 +444,7 @@ xpc_indicate_partition_disengaged_sn2(struct xpc_partition *part) /* * Send activate IRQ to get other side to see that we've cleared our - * bit in their engaged partitions AMO. + * bit in their engaged partitions amo. */ xpc_send_activate_IRQ_sn2(part_sn2->remote_amos_page_pa, cnodeid_to_nasid(0), @@ -452,9 +455,9 @@ xpc_indicate_partition_disengaged_sn2(struct xpc_partition *part) static int xpc_partition_engaged_sn2(short partid) { - AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; + struct amo *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; - /* our partition's AMO variable ANDed with partid mask */ + /* our partition's amo variable ANDed with partid mask */ return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & (1UL << partid)) != 0; } @@ -462,18 +465,18 @@ xpc_partition_engaged_sn2(short partid) static int xpc_any_partition_engaged_sn2(void) { - AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; + struct amo *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; - /* our partition's AMO variable */ + /* our partition's amo variable */ return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) != 0; } static void xpc_assume_partition_disengaged_sn2(short partid) { - AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; + struct amo *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; - /* clear bit(s) based on partid mask in our partition's AMO */ + /* clear bit(s) based on partid mask in our partition's amo */ FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, ~(1UL << partid)); } @@ -482,10 +485,10 @@ xpc_assume_partition_disengaged_sn2(short partid) static u64 xpc_prot_vec_sn2[MAX_NUMNODES]; /* - * Change protections to allow AMO operations on non-Shub 1.1 systems. + * Change protections to allow amo operations on non-Shub 1.1 systems. */ static enum xp_retval -xpc_allow_AMO_ops_sn2(AMO_t *amos_page) +xpc_allow_amo_ops_sn2(struct amo *amos_page) { u64 nasid_array = 0; int ret; @@ -493,7 +496,7 @@ xpc_allow_AMO_ops_sn2(AMO_t *amos_page) /* * On SHUB 1.1, we cannot call sn_change_memprotect() since the BIST * collides with memory operations. On those systems we call - * xpc_allow_AMO_ops_shub_wars_1_1_sn2() instead. + * xpc_allow_amo_ops_shub_wars_1_1_sn2() instead. */ if (!enable_shub_wars_1_1()) { ret = sn_change_memprotect(ia64_tpa((u64)amos_page), PAGE_SIZE, @@ -506,10 +509,10 @@ xpc_allow_AMO_ops_sn2(AMO_t *amos_page) } /* - * Change protections to allow AMO operations on Shub 1.1 systems. + * Change protections to allow amo operations on Shub 1.1 systems. */ static void -xpc_allow_AMO_ops_shub_wars_1_1_sn2(void) +xpc_allow_amo_ops_shub_wars_1_1_sn2(void) { int node; int nasid; @@ -536,7 +539,7 @@ xpc_allow_AMO_ops_shub_wars_1_1_sn2(void) static enum xp_retval xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) { - AMO_t *amos_page; + struct amo *amos_page; int i; int ret; @@ -549,32 +552,32 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) XPC_RP_VARS_SIZE); /* - * Before clearing xpc_vars, see if a page of AMOs had been previously + * Before clearing xpc_vars, see if a page of amos had been previously * allocated. If not we'll need to allocate one and set permissions - * so that cross-partition AMOs are allowed. + * so that cross-partition amos are allowed. * - * The allocated AMO page needs MCA reporting to remain disabled after + * The allocated amo page needs MCA reporting to remain disabled after * XPC has unloaded. To make this work, we keep a copy of the pointer * to this page (i.e., amos_page) in the struct xpc_vars structure, * which is pointed to by the reserved page, and re-use that saved copy - * on subsequent loads of XPC. This AMO page is never freed, and its + * on subsequent loads of XPC. This amo page is never freed, and its * memory protections are never restricted. */ amos_page = xpc_vars->amos_page; if (amos_page == NULL) { - amos_page = (AMO_t *)TO_AMO(uncached_alloc_page(0, 1)); + amos_page = (struct amo *)TO_AMO(uncached_alloc_page(0, 1)); if (amos_page == NULL) { - dev_err(xpc_part, "can't allocate page of AMOs\n"); + dev_err(xpc_part, "can't allocate page of amos\n"); return xpNoMemory; } /* - * Open up AMO-R/W to cpu. This is done on Shub 1.1 systems - * when xpc_allow_AMO_ops_shub_wars_1_1_sn2() is called. + * Open up amo-R/W to cpu. This is done on Shub 1.1 systems + * when xpc_allow_amo_ops_shub_wars_1_1_sn2() is called. */ - ret = xpc_allow_AMO_ops_sn2(amos_page); + ret = xpc_allow_amo_ops_sn2(amos_page); if (ret != xpSuccess) { - dev_err(xpc_part, "can't allow AMO operations\n"); + dev_err(xpc_part, "can't allow amo operations\n"); uncached_free_page(__IA64_UNCACHED_OFFSET | TO_PHYS((u64)amos_page), 1); return ret; @@ -595,11 +598,11 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) memset((u64 *)xpc_vars_part, 0, sizeof(struct xpc_vars_part_sn2) * xp_max_npartitions); - /* initialize the activate IRQ related AMO variables */ + /* initialize the activate IRQ related amo variables */ for (i = 0; i < xp_nasid_mask_words; i++) (void)xpc_init_IRQ_amo_sn2(XPC_ACTIVATE_IRQ_AMOS + i); - /* initialize the engaged remote partitions related AMO variables */ + /* initialize the engaged remote partitions related amo variables */ (void)xpc_init_IRQ_amo_sn2(XPC_ENGAGED_PARTITIONS_AMO); (void)xpc_init_IRQ_amo_sn2(XPC_DEACTIVATE_REQUEST_AMO); @@ -745,19 +748,20 @@ xpc_request_partition_deactivation_sn2(struct xpc_partition *part) { struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; unsigned long irq_flags; - AMO_t *amo = (AMO_t *)__va(part_sn2->remote_amos_page_pa + - (XPC_DEACTIVATE_REQUEST_AMO * sizeof(AMO_t))); + struct amo *amo = (struct amo *)__va(part_sn2->remote_amos_page_pa + + (XPC_DEACTIVATE_REQUEST_AMO * + sizeof(struct amo))); local_irq_save(irq_flags); - /* set bit corresponding to our partid in remote partition's AMO */ + /* set bit corresponding to our partid in remote partition's amo */ FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, (1UL << sn_partition_id)); /* * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we * didn't, we'd never know that the other partition is down and would - * keep sending IRQs and AMOs to it until the heartbeat times out. + * keep sending IRQs and amos to it until the heartbeat times out. */ (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> variable), @@ -767,7 +771,7 @@ xpc_request_partition_deactivation_sn2(struct xpc_partition *part) /* * Send activate IRQ to get other side to see that we've set our - * bit in their deactivate request AMO. + * bit in their deactivate request amo. */ xpc_send_activate_IRQ_sn2(part_sn2->remote_amos_page_pa, cnodeid_to_nasid(0), @@ -779,19 +783,20 @@ static void xpc_cancel_partition_deactivation_request_sn2(struct xpc_partition *part) { unsigned long irq_flags; - AMO_t *amo = (AMO_t *)__va(part->sn.sn2.remote_amos_page_pa + - (XPC_DEACTIVATE_REQUEST_AMO * sizeof(AMO_t))); + struct amo *amo = (struct amo *)__va(part->sn.sn2.remote_amos_page_pa + + (XPC_DEACTIVATE_REQUEST_AMO * + sizeof(struct amo))); local_irq_save(irq_flags); - /* clear bit corresponding to our partid in remote partition's AMO */ + /* clear bit corresponding to our partid in remote partition's amo */ FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, ~(1UL << sn_partition_id)); /* * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we * didn't, we'd never know that the other partition is down and would - * keep sending IRQs and AMOs to it until the heartbeat times out. + * keep sending IRQs and amos to it until the heartbeat times out. */ (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo-> variable), @@ -803,9 +808,9 @@ xpc_cancel_partition_deactivation_request_sn2(struct xpc_partition *part) static int xpc_partition_deactivation_requested_sn2(short partid) { - AMO_t *amo = xpc_vars->amos_page + XPC_DEACTIVATE_REQUEST_AMO; + struct amo *amo = xpc_vars->amos_page + XPC_DEACTIVATE_REQUEST_AMO; - /* our partition's AMO variable ANDed with partid mask */ + /* our partition's amo variable ANDed with partid mask */ return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & (1UL << partid)) != 0; } @@ -976,7 +981,7 @@ xpc_identify_activate_IRQ_req_sn2(int nasid) } /* - * Loop through the activation AMO variables and process any bits + * Loop through the activation amo variables and process any bits * which are set. Each bit indicates a nasid sending a partition * activation or deactivation request. * @@ -989,11 +994,11 @@ xpc_identify_activate_IRQ_sender_sn2(void) u64 nasid_mask; u64 nasid; /* remote nasid */ int n_IRQs_detected = 0; - AMO_t *act_amos; + struct amo *act_amos; act_amos = xpc_vars->amos_page + XPC_ACTIVATE_IRQ_AMOS; - /* scan through act AMO variable looking for non-zero entries */ + /* scan through act amo variable looking for non-zero entries */ for (word = 0; word < xp_nasid_mask_words; word++) { if (xpc_exiting) @@ -1005,7 +1010,7 @@ xpc_identify_activate_IRQ_sender_sn2(void) continue; } - dev_dbg(xpc_part, "AMO[%d] gave back 0x%lx\n", word, + dev_dbg(xpc_part, "amo[%d] gave back 0x%lx\n", word, nasid_mask); /* @@ -1038,7 +1043,7 @@ xpc_process_activate_IRQ_rcvd_sn2(int n_IRQs_expected) n_IRQs_detected = xpc_identify_activate_IRQ_sender_sn2(); if (n_IRQs_detected < n_IRQs_expected) { - /* retry once to help avoid missing AMO */ + /* retry once to help avoid missing amo */ (void)xpc_identify_activate_IRQ_sender_sn2(); } } @@ -1386,7 +1391,7 @@ xpc_pull_remote_vars_part_sn2(struct xpc_partition *part) part_sn2->remote_openclose_args_pa = pulled_entry->openclose_args_pa; part_sn2->remote_chctl_amo_va = - (AMO_t *)__va(pulled_entry->chctl_amo_pa); + (struct amo *)__va(pulled_entry->chctl_amo_pa); part_sn2->notify_IRQ_nasid = pulled_entry->notify_IRQ_nasid; part_sn2->notify_IRQ_phys_cpuid = pulled_entry->notify_IRQ_phys_cpuid; @@ -1417,7 +1422,7 @@ xpc_make_first_contact_sn2(struct xpc_partition *part) enum xp_retval ret; /* - * Register the remote partition's AMOs with SAL so it can handle + * Register the remote partition's amos with SAL so it can handle * and cleanup errors within that address range should the remote * partition go down. We don't unregister this range because it is * difficult to tell when outstanding writes to the remote partition @@ -2192,9 +2197,9 @@ xpc_init_sn2(void) xpc_send_msg = xpc_send_msg_sn2; xpc_received_msg = xpc_received_msg_sn2; - /* open up protections for IPI and [potentially] AMO operations */ + /* open up protections for IPI and [potentially] amo operations */ xpc_allow_IPI_ops_sn2(); - xpc_allow_AMO_ops_shub_wars_1_1_sn2(); + xpc_allow_amo_ops_shub_wars_1_1_sn2(); /* * This is safe to do before the xpc_hb_checker thread has started -- cgit v1.2.3 From 185c3a1b4bb4353529257f97caaeaac6c695e77d Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:11 -0700 Subject: sgi-xp: isolate allocation of XPC's msgqueues to sn2 only Move the allocation of XPC's msgqueues to xpc_sn2.c. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xpc.h | 3 +- drivers/misc/sgi-xp/xpc_channel.c | 197 ++---------------------------------- drivers/misc/sgi-xp/xpc_main.c | 2 + drivers/misc/sgi-xp/xpc_sn2.c | 205 +++++++++++++++++++++++++++++++++++--- 4 files changed, 204 insertions(+), 203 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index da2680892df..defd0888118 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -666,6 +666,8 @@ extern void (*xpc_online_heartbeat) (void); extern void (*xpc_check_remote_hb) (void); extern enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *); extern u64 (*xpc_get_chctl_all_flags) (struct xpc_partition *); +extern enum xp_retval (*xpc_allocate_msgqueues) (struct xpc_channel *); +extern void (*xpc_free_msgqueues) (struct xpc_channel *); extern void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *); extern void (*xpc_process_msg_chctl_flags) (struct xpc_partition *, int); extern int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *); @@ -728,7 +730,6 @@ extern void xpc_deactivate_partition(const int, struct xpc_partition *, extern enum xp_retval xpc_initiate_partid_to_nasids(short, void *); /* found in xpc_channel.c */ -extern void *xpc_kzalloc_cacheline_aligned(size_t, gfp_t, void **); extern void xpc_initiate_connect(int); extern void xpc_initiate_disconnect(int); extern enum xp_retval xpc_allocate_msg_wait(struct xpc_channel *); diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index 0d3c153d1d0..1c73423665b 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -24,145 +24,6 @@ #include #include "xpc.h" -/* - * Guarantee that the kzalloc'd memory is cacheline aligned. - */ -void * -xpc_kzalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) -{ - /* see if kzalloc will give us cachline aligned memory by default */ - *base = kzalloc(size, flags); - if (*base == NULL) - return NULL; - - if ((u64)*base == L1_CACHE_ALIGN((u64)*base)) - return *base; - - kfree(*base); - - /* nope, we'll have to do it ourselves */ - *base = kzalloc(size + L1_CACHE_BYTES, flags); - if (*base == NULL) - return NULL; - - return (void *)L1_CACHE_ALIGN((u64)*base); -} - -/* - * Allocate the local message queue and the notify queue. - */ -static enum xp_retval -xpc_allocate_local_msgqueue(struct xpc_channel *ch) -{ - unsigned long irq_flags; - int nentries; - size_t nbytes; - - for (nentries = ch->local_nentries; nentries > 0; nentries--) { - - nbytes = nentries * ch->msg_size; - ch->local_msgqueue = xpc_kzalloc_cacheline_aligned(nbytes, - GFP_KERNEL, - &ch->local_msgqueue_base); - if (ch->local_msgqueue == NULL) - continue; - - nbytes = nentries * sizeof(struct xpc_notify); - ch->notify_queue = kzalloc(nbytes, GFP_KERNEL); - if (ch->notify_queue == NULL) { - kfree(ch->local_msgqueue_base); - ch->local_msgqueue = NULL; - continue; - } - - spin_lock_irqsave(&ch->lock, irq_flags); - if (nentries < ch->local_nentries) { - dev_dbg(xpc_chan, "nentries=%d local_nentries=%d, " - "partid=%d, channel=%d\n", nentries, - ch->local_nentries, ch->partid, ch->number); - - ch->local_nentries = nentries; - } - spin_unlock_irqrestore(&ch->lock, irq_flags); - return xpSuccess; - } - - dev_dbg(xpc_chan, "can't get memory for local message queue and notify " - "queue, partid=%d, channel=%d\n", ch->partid, ch->number); - return xpNoMemory; -} - -/* - * Allocate the cached remote message queue. - */ -static enum xp_retval -xpc_allocate_remote_msgqueue(struct xpc_channel *ch) -{ - unsigned long irq_flags; - int nentries; - size_t nbytes; - - DBUG_ON(ch->remote_nentries <= 0); - - for (nentries = ch->remote_nentries; nentries > 0; nentries--) { - - nbytes = nentries * ch->msg_size; - ch->remote_msgqueue = xpc_kzalloc_cacheline_aligned(nbytes, - GFP_KERNEL, - &ch->remote_msgqueue_base); - if (ch->remote_msgqueue == NULL) - continue; - - spin_lock_irqsave(&ch->lock, irq_flags); - if (nentries < ch->remote_nentries) { - dev_dbg(xpc_chan, "nentries=%d remote_nentries=%d, " - "partid=%d, channel=%d\n", nentries, - ch->remote_nentries, ch->partid, ch->number); - - ch->remote_nentries = nentries; - } - spin_unlock_irqrestore(&ch->lock, irq_flags); - return xpSuccess; - } - - dev_dbg(xpc_chan, "can't get memory for cached remote message queue, " - "partid=%d, channel=%d\n", ch->partid, ch->number); - return xpNoMemory; -} - -/* - * Allocate message queues and other stuff associated with a channel. - * - * Note: Assumes all of the channel sizes are filled in. - */ -static enum xp_retval -xpc_allocate_msgqueues(struct xpc_channel *ch) -{ - unsigned long irq_flags; - enum xp_retval ret; - - DBUG_ON(ch->flags & XPC_C_SETUP); - - ret = xpc_allocate_local_msgqueue(ch); - if (ret != xpSuccess) - return ret; - - ret = xpc_allocate_remote_msgqueue(ch); - if (ret != xpSuccess) { - kfree(ch->local_msgqueue_base); - ch->local_msgqueue = NULL; - kfree(ch->notify_queue); - ch->notify_queue = NULL; - return ret; - } - - spin_lock_irqsave(&ch->lock, irq_flags); - ch->flags |= XPC_C_SETUP; - spin_unlock_irqrestore(&ch->lock, irq_flags); - - return xpSuccess; -} - /* * Process a connect message from a remote partition. * @@ -191,10 +52,11 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) if (ret != xpSuccess) XPC_DISCONNECT_CHANNEL(ch, ret, irq_flags); + ch->flags |= XPC_C_SETUP; + if (ch->flags & (XPC_C_CONNECTED | XPC_C_DISCONNECTING)) return; - DBUG_ON(!(ch->flags & XPC_C_SETUP)); DBUG_ON(ch->local_msgqueue == NULL); DBUG_ON(ch->remote_msgqueue == NULL); } @@ -219,55 +81,6 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) spin_lock_irqsave(&ch->lock, *irq_flags); } -/* - * Free up message queues and other stuff that were allocated for the specified - * channel. - * - * Note: ch->reason and ch->reason_line are left set for debugging purposes, - * they're cleared when XPC_C_DISCONNECTED is cleared. - */ -static void -xpc_free_msgqueues(struct xpc_channel *ch) -{ - struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; - - DBUG_ON(!spin_is_locked(&ch->lock)); - DBUG_ON(atomic_read(&ch->n_to_notify) != 0); - - ch->remote_msgqueue_pa = 0; - ch->func = NULL; - ch->key = NULL; - ch->msg_size = 0; - ch->local_nentries = 0; - ch->remote_nentries = 0; - ch->kthreads_assigned_limit = 0; - ch->kthreads_idle_limit = 0; - - ch_sn2->local_GP->get = 0; - ch_sn2->local_GP->put = 0; - ch_sn2->remote_GP.get = 0; - ch_sn2->remote_GP.put = 0; - ch_sn2->w_local_GP.get = 0; - ch_sn2->w_local_GP.put = 0; - ch_sn2->w_remote_GP.get = 0; - ch_sn2->w_remote_GP.put = 0; - ch_sn2->next_msg_to_pull = 0; - - if (ch->flags & XPC_C_SETUP) { - ch->flags &= ~XPC_C_SETUP; - - dev_dbg(xpc_chan, "ch->flags=0x%x, partid=%d, channel=%d\n", - ch->flags, ch->partid, ch->number); - - kfree(ch->local_msgqueue_base); - ch->local_msgqueue = NULL; - kfree(ch->remote_msgqueue_base); - ch->remote_msgqueue = NULL; - kfree(ch->notify_queue); - ch->notify_queue = NULL; - } -} - /* * spin_lock_irqsave() is expected to be held on entry. */ @@ -331,7 +144,11 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) /* it's now safe to free the channel's message queues */ xpc_free_msgqueues(ch); - /* mark disconnected, clear all other flags except XPC_C_WDISCONNECT */ + /* + * Mark the channel disconnected and clear all other flags, including + * XPC_C_SETUP (because of call to xpc_free_msgqueues()) but not + * including XPC_C_WDISCONNECT (if it was set). + */ ch->flags = (XPC_C_DISCONNECTED | (ch->flags & XPC_C_WDISCONNECT)); atomic_dec(&part->nchannels_active); diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index 2934b447300..b5f3c5e59db 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -186,6 +186,8 @@ void (*xpc_check_remote_hb) (void); enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *part); void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *ch); u64 (*xpc_get_chctl_all_flags) (struct xpc_partition *part); +enum xp_retval (*xpc_allocate_msgqueues) (struct xpc_channel *ch); +void (*xpc_free_msgqueues) (struct xpc_channel *ch); void (*xpc_process_msg_chctl_flags) (struct xpc_partition *part, int ch_number); int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *ch); struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *ch); diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index 01dd40ec2a8..e5dc8c44c6f 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -1048,6 +1048,30 @@ xpc_process_activate_IRQ_rcvd_sn2(int n_IRQs_expected) } } +/* + * Guarantee that the kzalloc'd memory is cacheline aligned. + */ +static void * +xpc_kzalloc_cacheline_aligned_sn2(size_t size, gfp_t flags, void **base) +{ + /* see if kzalloc will give us cachline aligned memory by default */ + *base = kzalloc(size, flags); + if (*base == NULL) + return NULL; + + if ((u64)*base == L1_CACHE_ALIGN((u64)*base)) + return *base; + + kfree(*base); + + /* nope, we'll have to do it ourselves */ + *base = kzalloc(size + L1_CACHE_BYTES, flags); + if (*base == NULL) + return NULL; + + return (void *)L1_CACHE_ALIGN((u64)*base); +} + /* * Setup the infrastructure necessary to support XPartition Communication * between the specified remote partition and the local one. @@ -1078,10 +1102,9 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) /* allocate all the required GET/PUT values */ - part_sn2->local_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, - GFP_KERNEL, - &part_sn2-> - local_GPs_base); + part_sn2->local_GPs = + xpc_kzalloc_cacheline_aligned_sn2(XPC_GP_SIZE, GFP_KERNEL, + &part_sn2->local_GPs_base); if (part_sn2->local_GPs == NULL) { dev_err(xpc_chan, "can't get memory for local get/put " "values\n"); @@ -1089,10 +1112,9 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) goto out_1; } - part_sn2->remote_GPs = xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, - GFP_KERNEL, - &part_sn2-> - remote_GPs_base); + part_sn2->remote_GPs = + xpc_kzalloc_cacheline_aligned_sn2(XPC_GP_SIZE, GFP_KERNEL, + &part_sn2->remote_GPs_base); if (part_sn2->remote_GPs == NULL) { dev_err(xpc_chan, "can't get memory for remote get/put " "values\n"); @@ -1105,8 +1127,9 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) /* allocate all the required open and close args */ part->local_openclose_args = - xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL, - &part->local_openclose_args_base); + xpc_kzalloc_cacheline_aligned_sn2(XPC_OPENCLOSE_ARGS_SIZE, + GFP_KERNEL, + &part->local_openclose_args_base); if (part->local_openclose_args == NULL) { dev_err(xpc_chan, "can't get memory for local connect args\n"); retval = xpNoMemory; @@ -1114,8 +1137,9 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) } part->remote_openclose_args = - xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE, GFP_KERNEL, - &part->remote_openclose_args_base); + xpc_kzalloc_cacheline_aligned_sn2(XPC_OPENCLOSE_ARGS_SIZE, + GFP_KERNEL, + &part->remote_openclose_args_base); if (part->remote_openclose_args == NULL) { dev_err(xpc_chan, "can't get memory for remote connect args\n"); retval = xpNoMemory; @@ -1527,6 +1551,161 @@ xpc_get_chctl_all_flags_sn2(struct xpc_partition *part) return chctl.all_flags; } +/* + * Allocate the local message queue and the notify queue. + */ +static enum xp_retval +xpc_allocate_local_msgqueue_sn2(struct xpc_channel *ch) +{ + unsigned long irq_flags; + int nentries; + size_t nbytes; + + for (nentries = ch->local_nentries; nentries > 0; nentries--) { + + nbytes = nentries * ch->msg_size; + ch->local_msgqueue = + xpc_kzalloc_cacheline_aligned_sn2(nbytes, GFP_KERNEL, + &ch->local_msgqueue_base); + if (ch->local_msgqueue == NULL) + continue; + + nbytes = nentries * sizeof(struct xpc_notify); + ch->notify_queue = kzalloc(nbytes, GFP_KERNEL); + if (ch->notify_queue == NULL) { + kfree(ch->local_msgqueue_base); + ch->local_msgqueue = NULL; + continue; + } + + spin_lock_irqsave(&ch->lock, irq_flags); + if (nentries < ch->local_nentries) { + dev_dbg(xpc_chan, "nentries=%d local_nentries=%d, " + "partid=%d, channel=%d\n", nentries, + ch->local_nentries, ch->partid, ch->number); + + ch->local_nentries = nentries; + } + spin_unlock_irqrestore(&ch->lock, irq_flags); + return xpSuccess; + } + + dev_dbg(xpc_chan, "can't get memory for local message queue and notify " + "queue, partid=%d, channel=%d\n", ch->partid, ch->number); + return xpNoMemory; +} + +/* + * Allocate the cached remote message queue. + */ +static enum xp_retval +xpc_allocate_remote_msgqueue_sn2(struct xpc_channel *ch) +{ + unsigned long irq_flags; + int nentries; + size_t nbytes; + + DBUG_ON(ch->remote_nentries <= 0); + + for (nentries = ch->remote_nentries; nentries > 0; nentries--) { + + nbytes = nentries * ch->msg_size; + ch->remote_msgqueue = + xpc_kzalloc_cacheline_aligned_sn2(nbytes, GFP_KERNEL, + &ch->remote_msgqueue_base); + if (ch->remote_msgqueue == NULL) + continue; + + spin_lock_irqsave(&ch->lock, irq_flags); + if (nentries < ch->remote_nentries) { + dev_dbg(xpc_chan, "nentries=%d remote_nentries=%d, " + "partid=%d, channel=%d\n", nentries, + ch->remote_nentries, ch->partid, ch->number); + + ch->remote_nentries = nentries; + } + spin_unlock_irqrestore(&ch->lock, irq_flags); + return xpSuccess; + } + + dev_dbg(xpc_chan, "can't get memory for cached remote message queue, " + "partid=%d, channel=%d\n", ch->partid, ch->number); + return xpNoMemory; +} + +/* + * Allocate message queues and other stuff associated with a channel. + * + * Note: Assumes all of the channel sizes are filled in. + */ +static enum xp_retval +xpc_allocate_msgqueues_sn2(struct xpc_channel *ch) +{ + enum xp_retval ret; + + DBUG_ON(ch->flags & XPC_C_SETUP); + + ret = xpc_allocate_local_msgqueue_sn2(ch); + if (ret == xpSuccess) { + + ret = xpc_allocate_remote_msgqueue_sn2(ch); + if (ret != xpSuccess) { + kfree(ch->local_msgqueue_base); + ch->local_msgqueue = NULL; + kfree(ch->notify_queue); + ch->notify_queue = NULL; + } + } + return ret; +} + +/* + * Free up message queues and other stuff that were allocated for the specified + * channel. + * + * Note: ch->reason and ch->reason_line are left set for debugging purposes, + * they're cleared when XPC_C_DISCONNECTED is cleared. + */ +static void +xpc_free_msgqueues_sn2(struct xpc_channel *ch) +{ + struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; + + DBUG_ON(!spin_is_locked(&ch->lock)); + DBUG_ON(atomic_read(&ch->n_to_notify) != 0); + + ch->remote_msgqueue_pa = 0; + ch->func = NULL; + ch->key = NULL; + ch->msg_size = 0; + ch->local_nentries = 0; + ch->remote_nentries = 0; + ch->kthreads_assigned_limit = 0; + ch->kthreads_idle_limit = 0; + + ch_sn2->local_GP->get = 0; + ch_sn2->local_GP->put = 0; + ch_sn2->remote_GP.get = 0; + ch_sn2->remote_GP.put = 0; + ch_sn2->w_local_GP.get = 0; + ch_sn2->w_local_GP.put = 0; + ch_sn2->w_remote_GP.get = 0; + ch_sn2->w_remote_GP.put = 0; + ch_sn2->next_msg_to_pull = 0; + + if (ch->flags & XPC_C_SETUP) { + dev_dbg(xpc_chan, "ch->flags=0x%x, partid=%d, channel=%d\n", + ch->flags, ch->partid, ch->number); + + kfree(ch->local_msgqueue_base); + ch->local_msgqueue = NULL; + kfree(ch->remote_msgqueue_base); + ch->remote_msgqueue = NULL; + kfree(ch->notify_queue); + ch->notify_queue = NULL; + } +} + /* * Notify those who wanted to be notified upon delivery of their message. */ @@ -2177,6 +2356,8 @@ xpc_init_sn2(void) xpc_teardown_infrastructure = xpc_teardown_infrastructure_sn2; xpc_make_first_contact = xpc_make_first_contact_sn2; xpc_get_chctl_all_flags = xpc_get_chctl_all_flags_sn2; + xpc_allocate_msgqueues = xpc_allocate_msgqueues_sn2; + xpc_free_msgqueues = xpc_free_msgqueues_sn2; xpc_notify_senders_of_disconnect = xpc_notify_senders_of_disconnect_sn2; xpc_process_msg_chctl_flags = xpc_process_msg_chctl_flags_sn2; xpc_n_of_deliverable_msgs = xpc_n_of_deliverable_msgs_sn2; -- cgit v1.2.3 From a7b4d509205db5e9cd3ffc77b306d7b10fe6a34d Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:12 -0700 Subject: sgi-xp: enable XPNET to handle more than 64 partitions Enable XPNET to support more than 64 partitions. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xpnet.c | 213 +++++++++++++++++++------------------------- 1 file changed, 94 insertions(+), 119 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index f9356ba7315..c5f59a6dae5 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -21,7 +21,6 @@ */ #include -#include #include #include #include @@ -32,8 +31,6 @@ #include #include #include -#include -#include #include #include "xp.h" @@ -104,7 +101,6 @@ struct xpnet_message { * then be released. */ struct xpnet_pending_msg { - struct list_head free_list; struct sk_buff *skb; atomic_t use_count; }; @@ -120,7 +116,7 @@ struct net_device *xpnet_device; * When we are notified of other partitions activating, we add them to * our bitmask of partitions to which we broadcast. */ -static u64 xpnet_broadcast_partitions; +static unsigned long *xpnet_broadcast_partitions; /* protect above */ static DEFINE_SPINLOCK(xpnet_broadcast_lock); @@ -140,16 +136,13 @@ static DEFINE_SPINLOCK(xpnet_broadcast_lock); #define XPNET_DEF_MTU (0x8000UL) /* - * The partition id is encapsulated in the MAC address. The following - * define locates the octet the partid is in. + * The partid is encapsulated in the MAC address beginning in the following + * octet and it consists of two octets. */ -#define XPNET_PARTID_OCTET 1 -#define XPNET_LICENSE_OCTET 2 +#define XPNET_PARTID_OCTET 2 + +/* Define the XPNET debug device structures to be used with dev_dbg() et al */ -/* - * Define the XPNET debug device structure that is to be used with dev_dbg(), - * dev_err(), dev_warn(), and dev_info(). - */ struct device_driver xpnet_dbg_name = { .name = "xpnet" }; @@ -231,7 +224,7 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) (void *)msg->buf_pa, msg->size); ret = xp_remote_memcpy((void *)((u64)skb->data & - ~(L1_CACHE_BYTES - 1)), + ~(L1_CACHE_BYTES - 1)), (void *)msg->buf_pa, msg->size); if (ret != xpSuccess) { @@ -283,8 +276,6 @@ static void xpnet_connection_activity(enum xp_retval reason, short partid, int channel, void *data, void *key) { - long bp; - DBUG_ON(partid < 0 || partid >= xp_max_npartitions); DBUG_ON(channel != XPC_NET_CHANNEL); @@ -297,31 +288,28 @@ xpnet_connection_activity(enum xp_retval reason, short partid, int channel, case xpConnected: /* connection completed to a partition */ spin_lock_bh(&xpnet_broadcast_lock); - xpnet_broadcast_partitions |= 1UL << (partid - 1); - bp = xpnet_broadcast_partitions; + __set_bit(partid, xpnet_broadcast_partitions); spin_unlock_bh(&xpnet_broadcast_lock); netif_carrier_on(xpnet_device); - dev_dbg(xpnet, "%s connection created to partition %d; " - "xpnet_broadcast_partitions=0x%lx\n", - xpnet_device->name, partid, bp); + dev_dbg(xpnet, "%s connected to partition %d\n", + xpnet_device->name, partid); break; default: spin_lock_bh(&xpnet_broadcast_lock); - xpnet_broadcast_partitions &= ~(1UL << (partid - 1)); - bp = xpnet_broadcast_partitions; + __clear_bit(partid, xpnet_broadcast_partitions); spin_unlock_bh(&xpnet_broadcast_lock); - if (bp == 0) + if (bitmap_empty((unsigned long *)xpnet_broadcast_partitions, + xp_max_npartitions)) { netif_carrier_off(xpnet_device); + } - dev_dbg(xpnet, "%s disconnected from partition %d; " - "xpnet_broadcast_partitions=0x%lx\n", - xpnet_device->name, partid, bp); + dev_dbg(xpnet, "%s disconnected from partition %d\n", + xpnet_device->name, partid); break; - } } @@ -424,36 +412,72 @@ xpnet_send_completed(enum xp_retval reason, short partid, int channel, } } +static void +xpnet_send(struct sk_buff *skb, struct xpnet_pending_msg *queued_msg, + u64 start_addr, u64 end_addr, u16 embedded_bytes, int dest_partid) +{ + u8 msg_buffer[XPNET_MSG_SIZE]; + struct xpnet_message *msg = (struct xpnet_message *)&msg_buffer; + enum xp_retval ret; + + msg->embedded_bytes = embedded_bytes; + if (unlikely(embedded_bytes != 0)) { + msg->version = XPNET_VERSION_EMBED; + dev_dbg(xpnet, "calling memcpy(0x%p, 0x%p, 0x%lx)\n", + &msg->data, skb->data, (size_t)embedded_bytes); + skb_copy_from_linear_data(skb, &msg->data, + (size_t)embedded_bytes); + } else { + msg->version = XPNET_VERSION; + } + msg->magic = XPNET_MAGIC; + msg->size = end_addr - start_addr; + msg->leadin_ignore = (u64)skb->data - start_addr; + msg->tailout_ignore = end_addr - (u64)skb_tail_pointer(skb); + msg->buf_pa = __pa(start_addr); + + dev_dbg(xpnet, "sending XPC message to %d:%d\n" + KERN_DEBUG "msg->buf_pa=0x%lx, msg->size=%u, " + "msg->leadin_ignore=%u, msg->tailout_ignore=%u\n", + dest_partid, XPC_NET_CHANNEL, msg->buf_pa, msg->size, + msg->leadin_ignore, msg->tailout_ignore); + + atomic_inc(&queued_msg->use_count); + + ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, XPC_NOWAIT, msg, + XPNET_MSG_SIZE, xpnet_send_completed, queued_msg); + if (unlikely(ret != xpSuccess)) + atomic_dec(&queued_msg->use_count); +} + /* * Network layer has formatted a packet (skb) and is ready to place it * "on the wire". Prepare and send an xpnet_message to all partitions * which have connected with us and are targets of this packet. * * MAC-NOTE: For the XPNET driver, the MAC address contains the - * destination partition_id. If the destination partition id word - * is 0xff, this packet is to broadcast to all partitions. + * destination partid. If the destination partid octets are 0xffff, + * this packet is to be broadcast to all connected partitions. */ static int xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct xpnet_pending_msg *queued_msg; - enum xp_retval ret; - u8 msg_buffer[XPNET_MSG_SIZE]; - struct xpnet_message *msg = (struct xpnet_message *)&msg_buffer[0]; u64 start_addr, end_addr; - long dp; - u8 second_mac_octet; short dest_partid; - struct xpnet_dev_private *priv; - u16 embedded_bytes; - - priv = (struct xpnet_dev_private *)dev->priv; + struct xpnet_dev_private *priv = (struct xpnet_dev_private *)dev->priv; + u16 embedded_bytes = 0; dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p " "skb->end=0x%p skb->len=%d\n", (void *)skb->head, (void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), skb->len); + if (skb->data[0] == 0x33) { + dev_kfree_skb(skb); + return 0; /* nothing needed to be done */ + } + /* * The xpnet_pending_msg tracks how many outstanding * xpc_send_notifies are relying on this skb. When none @@ -465,7 +489,6 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) "packet\n", sizeof(struct xpnet_pending_msg)); priv->stats.tx_errors++; - return -ENOMEM; } @@ -474,7 +497,6 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) end_addr = L1_CACHE_ALIGN((u64)skb_tail_pointer(skb)); /* calculate how many bytes to embed in the XPC message */ - embedded_bytes = 0; if (unlikely(skb->len <= XPNET_MSG_DATA_MAX)) { /* skb->data does fit so embed */ embedded_bytes = skb->len; @@ -490,78 +512,28 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) atomic_set(&queued_msg->use_count, 1); queued_msg->skb = skb; - second_mac_octet = skb->data[XPNET_PARTID_OCTET]; - if (second_mac_octet == 0xff) { + if (skb->data[0] == 0xff) { /* we are being asked to broadcast to all partitions */ - dp = xpnet_broadcast_partitions; - } else if (second_mac_octet != 0) { - dp = xpnet_broadcast_partitions & - (1UL << (second_mac_octet - 1)); - } else { - /* 0 is an invalid partid. Ignore */ - dp = 0; - } - dev_dbg(xpnet, "destination Partitions mask (dp) = 0x%lx\n", dp); - - /* - * If we wanted to allow promiscuous mode to work like an - * unswitched network, this would be a good point to OR in a - * mask of partitions which should be receiving all packets. - */ - - /* - * Main send loop. - */ - for (dest_partid = 0; dp && dest_partid < xp_max_npartitions; - dest_partid++) { + for_each_bit(dest_partid, xpnet_broadcast_partitions, + xp_max_npartitions) { - if (!(dp & (1UL << (dest_partid - 1)))) { - /* not destined for this partition */ - continue; + xpnet_send(skb, queued_msg, start_addr, end_addr, + embedded_bytes, dest_partid); } + } else { + dest_partid = (short)skb->data[XPNET_PARTID_OCTET + 1]; + dest_partid |= (short)skb->data[XPNET_PARTID_OCTET + 0] << 8; - /* remove this partition from the destinations mask */ - dp &= ~(1UL << (dest_partid - 1)); - - /* found a partition to send to */ + if (dest_partid >= 0 && + dest_partid < xp_max_npartitions && + test_bit(dest_partid, xpnet_broadcast_partitions) != 0) { - msg->embedded_bytes = embedded_bytes; - if (unlikely(embedded_bytes != 0)) { - msg->version = XPNET_VERSION_EMBED; - dev_dbg(xpnet, "calling memcpy(0x%p, 0x%p, 0x%lx)\n", - &msg->data, skb->data, (size_t)embedded_bytes); - skb_copy_from_linear_data(skb, &msg->data, - (size_t)embedded_bytes); - } else { - msg->version = XPNET_VERSION; - } - msg->magic = XPNET_MAGIC; - msg->size = end_addr - start_addr; - msg->leadin_ignore = (u64)skb->data - start_addr; - msg->tailout_ignore = end_addr - (u64)skb_tail_pointer(skb); - msg->buf_pa = __pa(start_addr); - - dev_dbg(xpnet, "sending XPC message to %d:%d\n" - KERN_DEBUG "msg->buf_pa=0x%lx, msg->size=%u, " - "msg->leadin_ignore=%u, msg->tailout_ignore=%u\n", - dest_partid, XPC_NET_CHANNEL, msg->buf_pa, msg->size, - msg->leadin_ignore, msg->tailout_ignore); - - atomic_inc(&queued_msg->use_count); - - ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, XPC_NOWAIT, - &msg, sizeof(msg) + embedded_bytes - 1, - xpnet_send_completed, queued_msg); - if (unlikely(ret != xpSuccess)) { - atomic_dec(&queued_msg->use_count); - continue; + xpnet_send(skb, queued_msg, start_addr, end_addr, + embedded_bytes, dest_partid); } } if (atomic_dec_return(&queued_msg->use_count) == 0) { - dev_dbg(xpnet, "no partitions to receive packet destined for " - "%d\n", dest_partid); - dev_kfree_skb(skb); kfree(queued_msg); } @@ -589,23 +561,28 @@ xpnet_dev_tx_timeout(struct net_device *dev) static int __init xpnet_init(void) { - int i; - u32 license_num; - int result = -ENOMEM; + int result; - if (!ia64_platform_is("sn2")) + if (!is_shub() && !is_uv()) return -ENODEV; dev_info(xpnet, "registering network device %s\n", XPNET_DEVICE_NAME); + xpnet_broadcast_partitions = kzalloc(BITS_TO_LONGS(xp_max_npartitions) * + sizeof(long), GFP_KERNEL); + if (xpnet_broadcast_partitions == NULL) + return -ENOMEM; + /* * use ether_setup() to init the majority of our device * structure and then override the necessary pieces. */ xpnet_device = alloc_netdev(sizeof(struct xpnet_dev_private), XPNET_DEVICE_NAME, ether_setup); - if (xpnet_device == NULL) + if (xpnet_device == NULL) { + kfree(xpnet_broadcast_partitions); return -ENOMEM; + } netif_carrier_off(xpnet_device); @@ -623,14 +600,10 @@ xpnet_init(void) * MAC addresses. We chose the first octet of the MAC to be unlikely * to collide with any vendor's officially issued MAC. */ - xpnet_device->dev_addr[0] = 0xfe; - xpnet_device->dev_addr[XPNET_PARTID_OCTET] = sn_partition_id; - license_num = sn_partition_serial_number_val(); - for (i = 3; i >= 0; i--) { - xpnet_device->dev_addr[XPNET_LICENSE_OCTET + i] = - license_num & 0xff; - license_num = license_num >> 8; - } + xpnet_device->dev_addr[0] = 0x02; /* locally administered, no OUI */ + + xpnet_device->dev_addr[XPNET_PARTID_OCTET + 1] = sn_partition_id; + xpnet_device->dev_addr[XPNET_PARTID_OCTET + 0] = (sn_partition_id >> 8); /* * ether_setup() sets this to a multicast device. We are @@ -646,8 +619,10 @@ xpnet_init(void) xpnet_device->features = NETIF_F_NO_CSUM; result = register_netdev(xpnet_device); - if (result != 0) + if (result != 0) { free_netdev(xpnet_device); + kfree(xpnet_broadcast_partitions); + } return result; } @@ -661,8 +636,8 @@ xpnet_exit(void) xpnet_device[0].name); unregister_netdev(xpnet_device); - free_netdev(xpnet_device); + kfree(xpnet_broadcast_partitions); } module_exit(xpnet_exit); -- cgit v1.2.3 From ee6665e3b6e1283c30ae240732af1345bc02154e Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:13 -0700 Subject: sgi-xp: isolate remote copy buffer to sn2 only Make the remote copy buffer an sn2 only item. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xp.h | 10 ----- drivers/misc/sgi-xp/xpc.h | 39 ++++------------ drivers/misc/sgi-xp/xpc_main.c | 31 ++++--------- drivers/misc/sgi-xp/xpc_partition.c | 31 +++++-------- drivers/misc/sgi-xp/xpc_sn2.c | 88 +++++++++++++++++++++++++++++-------- 5 files changed, 97 insertions(+), 102 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index 43bf2470850..955b5b91323 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -60,16 +60,6 @@ #define XP_MAX_NPARTITIONS_SN2 64 #define XP_MAX_NPARTITIONS_UV 256 -/* - * Define the number of u64s required to represent all the C-brick nasids - * as a bitmap. The cross-partition kernel modules deal only with - * C-brick nasids, thus the need for bitmaps which don't account for - * odd-numbered (non C-brick) nasids. - */ -#define XP_MAX_PHYSNODE_ID (MAX_NUMALINK_NODES / 2) -#define XP_NASID_MASK_BYTES ((XP_MAX_PHYSNODE_ID + 7) / 8) -#define XP_NASID_MASK_WORDS ((XP_MAX_PHYSNODE_ID + 63) / 64) - /* * XPC establishes channel connections between the local partition and any * other partition that is currently up. Over these channels, kernel-level diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index defd0888118..2111723553b 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -150,26 +150,6 @@ struct xpc_vars_sn2 { #define XPC_V_VERSION _XPC_VERSION(3, 1) /* version 3.1 of the cross vars */ -/* - * The following pertains to ia64-sn2 only. - * - * Memory for XPC's amo variables is allocated by the MSPEC driver. These - * pages are located in the lowest granule. The lowest granule uses 4k pages - * for cached references and an alternate TLB handler to never provide a - * cacheable mapping for the entire region. This will prevent speculative - * reading of cached copies of our lines from being issued which will cause - * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64 - * amo variables (based on XP_MAX_NPARTITIONS_SN2) to identify the senders of - * NOTIFY IRQs, 128 amo variables (based on XP_NASID_MASK_WORDS) to identify - * the senders of ACTIVATE IRQs, 1 amo variable to identify which remote - * partitions (i.e., XPCs) consider themselves currently engaged with the - * local XPC and 1 amo variable to request partition deactivation. - */ -#define XPC_NOTIFY_IRQ_AMOS 0 -#define XPC_ACTIVATE_IRQ_AMOS (XPC_NOTIFY_IRQ_AMOS + XP_MAX_NPARTITIONS_SN2) -#define XPC_ENGAGED_PARTITIONS_AMO (XPC_ACTIVATE_IRQ_AMOS + XP_NASID_MASK_WORDS) -#define XPC_DEACTIVATE_REQUEST_AMO (XPC_ENGAGED_PARTITIONS_AMO + 1) - /* * The following structure describes the per partition specific variables. * @@ -214,9 +194,10 @@ struct xpc_vars_part_sn2 { #define XPC_RP_VARS_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_vars_sn2)) #define XPC_RP_PART_NASIDS(_rp) ((u64 *)((u8 *)(_rp) + XPC_RP_HEADER_SIZE)) -#define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + xp_nasid_mask_words) -#define XPC_RP_VARS(_rp) ((struct xpc_vars_sn2 *)(XPC_RP_MACH_NASIDS(_rp) + \ - xp_nasid_mask_words)) +#define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + xpc_nasid_mask_words) +#define XPC_RP_VARS(_rp) ((struct xpc_vars_sn2 *) \ + (XPC_RP_MACH_NASIDS(_rp) + \ + xpc_nasid_mask_words)) /* * Functions registered by add_timer() or called by kernel_thread() only @@ -225,11 +206,11 @@ struct xpc_vars_part_sn2 { * the passed argument. */ #define XPC_PACK_ARGS(_arg1, _arg2) \ - ((((u64) _arg1) & 0xffffffff) | \ - ((((u64) _arg2) & 0xffffffff) << 32)) + ((((u64)_arg1) & 0xffffffff) | \ + ((((u64)_arg2) & 0xffffffff) << 32)) -#define XPC_UNPACK_ARG1(_args) (((u64) _args) & 0xffffffff) -#define XPC_UNPACK_ARG2(_args) ((((u64) _args) >> 32) & 0xffffffff) +#define XPC_UNPACK_ARG1(_args) (((u64)_args) & 0xffffffff) +#define XPC_UNPACK_ARG2(_args) ((((u64)_args) >> 32) & 0xffffffff) /* * Define a Get/Put value pair (pointers) used with a message queue. @@ -710,12 +691,10 @@ extern void xpc_exit_uv(void); /* found in xpc_partition.c */ extern int xpc_exiting; -extern int xp_nasid_mask_words; +extern int xpc_nasid_mask_words; extern struct xpc_rsvd_page *xpc_rsvd_page; extern u64 *xpc_mach_nasids; extern struct xpc_partition *xpc_partitions; -extern char *xpc_remote_copy_buffer; -extern void *xpc_remote_copy_buffer_base; extern void *xpc_kmalloc_cacheline_aligned(size_t, gfp_t, void **); extern struct xpc_rsvd_page *xpc_setup_rsvd_page(void); extern int xpc_identify_activate_IRQ_sender(void); diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index b5f3c5e59db..36dfccea524 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -877,7 +877,6 @@ xpc_do_exit(enum xp_retval reason) unregister_sysctl_table(xpc_sysctl); kfree(xpc_partitions); - kfree(xpc_remote_copy_buffer_base); if (is_shub()) xpc_exit_sn2(); @@ -1031,7 +1030,9 @@ xpc_init(void) short partid; struct xpc_partition *part; struct task_struct *kthread; - size_t buf_size; + + snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part"); + snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan"); if (is_shub()) { /* @@ -1054,26 +1055,12 @@ xpc_init(void) return -ENODEV; } - snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part"); - snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan"); - - buf_size = max(XPC_RP_VARS_SIZE, - XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES); - xpc_remote_copy_buffer = xpc_kmalloc_cacheline_aligned(buf_size, - GFP_KERNEL, - &xpc_remote_copy_buffer_base); - if (xpc_remote_copy_buffer == NULL) { - dev_err(xpc_part, "can't get memory for remote copy buffer\n"); - ret = -ENOMEM; - goto out_1; - } - xpc_partitions = kzalloc(sizeof(struct xpc_partition) * xp_max_npartitions, GFP_KERNEL); if (xpc_partitions == NULL) { dev_err(xpc_part, "can't get memory for partition structure\n"); ret = -ENOMEM; - goto out_2; + goto out_1; } /* @@ -1115,7 +1102,7 @@ xpc_init(void) if (xpc_rsvd_page == NULL) { dev_err(xpc_part, "can't setup our reserved page\n"); ret = -EBUSY; - goto out_3; + goto out_2; } /* add ourselves to the reboot_notifier_list */ @@ -1136,7 +1123,7 @@ xpc_init(void) if (IS_ERR(kthread)) { dev_err(xpc_part, "failed while forking hb check thread\n"); ret = -EBUSY; - goto out_4; + goto out_3; } /* @@ -1164,18 +1151,16 @@ xpc_init(void) return 0; /* initialization was not successful */ -out_4: +out_3: /* indicate to others that our reserved page is uninitialized */ xpc_rsvd_page->stamp = 0; (void)unregister_die_notifier(&xpc_die_notifier); (void)unregister_reboot_notifier(&xpc_reboot_notifier); -out_3: +out_2: if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); kfree(xpc_partitions); -out_2: - kfree(xpc_remote_copy_buffer_base); out_1: if (is_shub()) xpc_exit_sn2(); diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index c769ab8f74e..9f104450478 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -34,20 +34,11 @@ struct xpc_rsvd_page *xpc_rsvd_page; static u64 *xpc_part_nasids; u64 *xpc_mach_nasids; -/* >>> next two variables should be 'xpc_' if they remain here */ -static int xp_sizeof_nasid_mask; /* actual size in bytes of nasid mask */ -int xp_nasid_mask_words; /* actual size in words of nasid mask */ +static int xpc_sizeof_nasid_mask; /* actual size in bytes of nasid mask */ +int xpc_nasid_mask_words; /* actual size in words of nasid mask */ struct xpc_partition *xpc_partitions; -/* - * Generic buffer used to store a local copy of portions of a remote - * partition's reserved page (either its header and part_nasids mask, - * or its vars). - */ -char *xpc_remote_copy_buffer; -void *xpc_remote_copy_buffer_base; - /* * Guarantee that the kmalloc'd memory is cacheline aligned. */ @@ -176,9 +167,9 @@ xpc_setup_rsvd_page(void) /* SAL_version 1 didn't set the nasids_size field */ rp->SAL_nasids_size = 128; } - xp_sizeof_nasid_mask = rp->SAL_nasids_size; - xp_nasid_mask_words = DIV_ROUND_UP(xp_sizeof_nasid_mask, - BYTES_PER_WORD); + xpc_sizeof_nasid_mask = rp->SAL_nasids_size; + xpc_nasid_mask_words = DIV_ROUND_UP(xpc_sizeof_nasid_mask, + BYTES_PER_WORD); /* setup the pointers to the various items in the reserved page */ xpc_part_nasids = XPC_RP_PART_NASIDS(rp); @@ -222,14 +213,14 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, /* pull over the reserved page header and part_nasids mask */ ret = xp_remote_memcpy(remote_rp, (void *)*remote_rp_pa, - XPC_RP_HEADER_SIZE + xp_sizeof_nasid_mask); + XPC_RP_HEADER_SIZE + xpc_sizeof_nasid_mask); if (ret != xpSuccess) return ret; if (discovered_nasids != NULL) { u64 *remote_part_nasids = XPC_RP_PART_NASIDS(remote_rp); - for (i = 0; i < xp_nasid_mask_words; i++) + for (i = 0; i < xpc_nasid_mask_words; i++) discovered_nasids[i] |= remote_part_nasids[i]; } @@ -414,12 +405,12 @@ xpc_discovery(void) enum xp_retval ret; remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE + - xp_sizeof_nasid_mask, + xpc_sizeof_nasid_mask, GFP_KERNEL, &remote_rp_base); if (remote_rp == NULL) return; - discovered_nasids = kzalloc(sizeof(u64) * xp_nasid_mask_words, + discovered_nasids = kzalloc(sizeof(u64) * xpc_nasid_mask_words, GFP_KERNEL); if (discovered_nasids == NULL) { kfree(remote_rp_base); @@ -521,10 +512,10 @@ xpc_initiate_partid_to_nasids(short partid, void *nasid_mask) if (part->remote_rp_pa == 0) return xpPartitionDown; - memset(nasid_mask, 0, XP_NASID_MASK_BYTES); + memset(nasid_mask, 0, xpc_sizeof_nasid_mask); part_nasid_pa = (u64)XPC_RP_PART_NASIDS(part->remote_rp_pa); return xp_remote_memcpy(nasid_mask, (void *)part_nasid_pa, - xp_sizeof_nasid_mask); + xpc_sizeof_nasid_mask); } diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index e5dc8c44c6f..9c0c29a2ac8 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -19,6 +19,43 @@ #include #include "xpc.h" +/* + * Define the number of u64s required to represent all the C-brick nasids + * as a bitmap. The cross-partition kernel modules deal only with + * C-brick nasids, thus the need for bitmaps which don't account for + * odd-numbered (non C-brick) nasids. + */ +#define XPC_MAX_PHYSNODES_SN2 (MAX_NUMALINK_NODES / 2) +#define XP_NASID_MASK_BYTES_SN2 ((XPC_MAX_PHYSNODES_SN2 + 7) / 8) +#define XP_NASID_MASK_WORDS_SN2 ((XPC_MAX_PHYSNODES_SN2 + 63) / 64) + +/* + * Memory for XPC's amo variables is allocated by the MSPEC driver. These + * pages are located in the lowest granule. The lowest granule uses 4k pages + * for cached references and an alternate TLB handler to never provide a + * cacheable mapping for the entire region. This will prevent speculative + * reading of cached copies of our lines from being issued which will cause + * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64 + * amo variables (based on XP_MAX_NPARTITIONS_SN2) to identify the senders of + * NOTIFY IRQs, 128 amo variables (based on XP_NASID_MASK_WORDS_SN2) to identify + * the senders of ACTIVATE IRQs, 1 amo variable to identify which remote + * partitions (i.e., XPCs) consider themselves currently engaged with the + * local XPC and 1 amo variable to request partition deactivation. + */ +#define XPC_NOTIFY_IRQ_AMOS_SN2 0 +#define XPC_ACTIVATE_IRQ_AMOS_SN2 (XPC_NOTIFY_IRQ_AMOS_SN2 + \ + XP_MAX_NPARTITIONS_SN2) +#define XPC_ENGAGED_PARTITIONS_AMO_SN2 (XPC_ACTIVATE_IRQ_AMOS_SN2 + \ + XP_NASID_MASK_WORDS_SN2) +#define XPC_DEACTIVATE_REQUEST_AMO_SN2 (XPC_ENGAGED_PARTITIONS_AMO_SN2 + 1) + +/* + * Buffer used to store a local copy of portions of a remote partition's + * reserved page (either its header and part_nasids mask, or its vars). + */ +static char *xpc_remote_copy_buffer_sn2; +static void *xpc_remote_copy_buffer_base_sn2; + static struct xpc_vars_sn2 *xpc_vars; /* >>> Add _sn2 suffix? */ static struct xpc_vars_part_sn2 *xpc_vars_part; /* >>> Add _sn2 suffix? */ @@ -176,7 +213,7 @@ xpc_send_activate_IRQ_sn2(u64 amos_page_pa, int from_nasid, int to_nasid, int w_index = XPC_NASID_W_INDEX(from_nasid); int b_index = XPC_NASID_B_INDEX(from_nasid); struct amo *amos = (struct amo *)__va(amos_page_pa + - (XPC_ACTIVATE_IRQ_AMOS * + (XPC_ACTIVATE_IRQ_AMOS_SN2 * sizeof(struct amo))); (void)xpc_send_IRQ_sn2(&amos[w_index], (1UL << b_index), to_nasid, @@ -189,7 +226,7 @@ xpc_send_local_activate_IRQ_sn2(int from_nasid) int w_index = XPC_NASID_W_INDEX(from_nasid); int b_index = XPC_NASID_B_INDEX(from_nasid); struct amo *amos = (struct amo *)__va(xpc_vars->amos_page_pa + - (XPC_ACTIVATE_IRQ_AMOS * + (XPC_ACTIVATE_IRQ_AMOS_SN2 * sizeof(struct amo))); /* fake the sending and receipt of an activate IRQ from remote nasid */ @@ -395,7 +432,7 @@ xpc_indicate_partition_engaged_sn2(struct xpc_partition *part) { unsigned long irq_flags; struct amo *amo = (struct amo *)__va(part->sn.sn2.remote_amos_page_pa + - (XPC_ENGAGED_PARTITIONS_AMO * + (XPC_ENGAGED_PARTITIONS_AMO_SN2 * sizeof(struct amo))); local_irq_save(irq_flags); @@ -422,7 +459,7 @@ xpc_indicate_partition_disengaged_sn2(struct xpc_partition *part) struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; unsigned long irq_flags; struct amo *amo = (struct amo *)__va(part_sn2->remote_amos_page_pa + - (XPC_ENGAGED_PARTITIONS_AMO * + (XPC_ENGAGED_PARTITIONS_AMO_SN2 * sizeof(struct amo))); local_irq_save(irq_flags); @@ -455,7 +492,7 @@ xpc_indicate_partition_disengaged_sn2(struct xpc_partition *part) static int xpc_partition_engaged_sn2(short partid) { - struct amo *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; + struct amo *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO_SN2; /* our partition's amo variable ANDed with partid mask */ return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & @@ -465,7 +502,7 @@ xpc_partition_engaged_sn2(short partid) static int xpc_any_partition_engaged_sn2(void) { - struct amo *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; + struct amo *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO_SN2; /* our partition's amo variable */ return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) != 0; @@ -474,7 +511,7 @@ xpc_any_partition_engaged_sn2(void) static void xpc_assume_partition_disengaged_sn2(short partid) { - struct amo *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO; + struct amo *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO_SN2; /* clear bit(s) based on partid mask in our partition's amo */ FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, @@ -599,12 +636,12 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) xp_max_npartitions); /* initialize the activate IRQ related amo variables */ - for (i = 0; i < xp_nasid_mask_words; i++) - (void)xpc_init_IRQ_amo_sn2(XPC_ACTIVATE_IRQ_AMOS + i); + for (i = 0; i < xpc_nasid_mask_words; i++) + (void)xpc_init_IRQ_amo_sn2(XPC_ACTIVATE_IRQ_AMOS_SN2 + i); /* initialize the engaged remote partitions related amo variables */ - (void)xpc_init_IRQ_amo_sn2(XPC_ENGAGED_PARTITIONS_AMO); - (void)xpc_init_IRQ_amo_sn2(XPC_DEACTIVATE_REQUEST_AMO); + (void)xpc_init_IRQ_amo_sn2(XPC_ENGAGED_PARTITIONS_AMO_SN2); + (void)xpc_init_IRQ_amo_sn2(XPC_DEACTIVATE_REQUEST_AMO_SN2); return xpSuccess; } @@ -657,7 +694,7 @@ xpc_check_remote_hb_sn2(void) short partid; enum xp_retval ret; - remote_vars = (struct xpc_vars_sn2 *)xpc_remote_copy_buffer; + remote_vars = (struct xpc_vars_sn2 *)xpc_remote_copy_buffer_sn2; for (partid = 0; partid < xp_max_npartitions; partid++) { @@ -749,7 +786,7 @@ xpc_request_partition_deactivation_sn2(struct xpc_partition *part) struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; unsigned long irq_flags; struct amo *amo = (struct amo *)__va(part_sn2->remote_amos_page_pa + - (XPC_DEACTIVATE_REQUEST_AMO * + (XPC_DEACTIVATE_REQUEST_AMO_SN2 * sizeof(struct amo))); local_irq_save(irq_flags); @@ -784,7 +821,7 @@ xpc_cancel_partition_deactivation_request_sn2(struct xpc_partition *part) { unsigned long irq_flags; struct amo *amo = (struct amo *)__va(part->sn.sn2.remote_amos_page_pa + - (XPC_DEACTIVATE_REQUEST_AMO * + (XPC_DEACTIVATE_REQUEST_AMO_SN2 * sizeof(struct amo))); local_irq_save(irq_flags); @@ -808,7 +845,7 @@ xpc_cancel_partition_deactivation_request_sn2(struct xpc_partition *part) static int xpc_partition_deactivation_requested_sn2(short partid) { - struct amo *amo = xpc_vars->amos_page + XPC_DEACTIVATE_REQUEST_AMO; + struct amo *amo = xpc_vars->amos_page + XPC_DEACTIVATE_REQUEST_AMO_SN2; /* our partition's amo variable ANDed with partid mask */ return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & @@ -898,7 +935,7 @@ xpc_identify_activate_IRQ_req_sn2(int nasid) /* pull over the reserved page structure */ - remote_rp = (struct xpc_rsvd_page *)xpc_remote_copy_buffer; + remote_rp = (struct xpc_rsvd_page *)xpc_remote_copy_buffer_sn2; ret = xpc_get_remote_rp(nasid, NULL, remote_rp, &remote_rp_pa); if (ret != xpSuccess) { @@ -917,7 +954,7 @@ xpc_identify_activate_IRQ_req_sn2(int nasid) /* pull over the cross partition variables */ - remote_vars = (struct xpc_vars_sn2 *)xpc_remote_copy_buffer; + remote_vars = (struct xpc_vars_sn2 *)xpc_remote_copy_buffer_sn2; ret = xpc_get_remote_vars_sn2(remote_vars_pa, remote_vars); if (ret != xpSuccess) { @@ -996,10 +1033,10 @@ xpc_identify_activate_IRQ_sender_sn2(void) int n_IRQs_detected = 0; struct amo *act_amos; - act_amos = xpc_vars->amos_page + XPC_ACTIVATE_IRQ_AMOS; + act_amos = xpc_vars->amos_page + XPC_ACTIVATE_IRQ_AMOS_SN2; /* scan through act amo variable looking for non-zero entries */ - for (word = 0; word < xp_nasid_mask_words; word++) { + for (word = 0; word < xpc_nasid_mask_words; word++) { if (xpc_exiting) break; @@ -2334,6 +2371,7 @@ int xpc_init_sn2(void) { int ret; + size_t buf_size; xpc_rsvd_page_init = xpc_rsvd_page_init_sn2; xpc_increment_heartbeat = xpc_increment_heartbeat_sn2; @@ -2378,6 +2416,16 @@ xpc_init_sn2(void) xpc_send_msg = xpc_send_msg_sn2; xpc_received_msg = xpc_received_msg_sn2; + buf_size = max(XPC_RP_VARS_SIZE, + XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES_SN2); + xpc_remote_copy_buffer_sn2 = xpc_kmalloc_cacheline_aligned(buf_size, + GFP_KERNEL, + &xpc_remote_copy_buffer_base_sn2); + if (xpc_remote_copy_buffer_sn2 == NULL) { + dev_err(xpc_part, "can't get memory for remote copy buffer\n"); + return -ENOMEM; + } + /* open up protections for IPI and [potentially] amo operations */ xpc_allow_IPI_ops_sn2(); xpc_allow_amo_ops_shub_wars_1_1_sn2(); @@ -2394,6 +2442,7 @@ xpc_init_sn2(void) dev_err(xpc_part, "can't register ACTIVATE IRQ handler, " "errno=%d\n", -ret); xpc_disallow_IPI_ops_sn2(); + kfree(xpc_remote_copy_buffer_base_sn2); } return ret; } @@ -2403,4 +2452,5 @@ xpc_exit_sn2(void) { free_irq(SGI_XPC_ACTIVATE, NULL); xpc_disallow_IPI_ops_sn2(); + kfree(xpc_remote_copy_buffer_base_sn2); } -- cgit v1.2.3 From 8e85c23ef04fe0d8414e0b1dc04543095282a27a Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:13 -0700 Subject: sgi-xp: add _sn2 suffix to a few variables Add an '_sn2' suffix to some variables found in xpc_sn2.c. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xpc_sn2.c | 124 ++++++++++++++++++++++-------------------- 1 file changed, 65 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index 9c0c29a2ac8..63fe59a5bfa 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -56,15 +56,15 @@ static char *xpc_remote_copy_buffer_sn2; static void *xpc_remote_copy_buffer_base_sn2; -static struct xpc_vars_sn2 *xpc_vars; /* >>> Add _sn2 suffix? */ -static struct xpc_vars_part_sn2 *xpc_vars_part; /* >>> Add _sn2 suffix? */ +static struct xpc_vars_sn2 *xpc_vars_sn2; +static struct xpc_vars_part_sn2 *xpc_vars_part_sn2; /* SH_IPI_ACCESS shub register value on startup */ -static u64 xpc_sh1_IPI_access; -static u64 xpc_sh2_IPI_access0; -static u64 xpc_sh2_IPI_access1; -static u64 xpc_sh2_IPI_access2; -static u64 xpc_sh2_IPI_access3; +static u64 xpc_sh1_IPI_access_sn2; +static u64 xpc_sh2_IPI_access0_sn2; +static u64 xpc_sh2_IPI_access1_sn2; +static u64 xpc_sh2_IPI_access2_sn2; +static u64 xpc_sh2_IPI_access3_sn2; /* * Change protections to allow IPI operations. @@ -77,13 +77,13 @@ xpc_allow_IPI_ops_sn2(void) /* >>> The following should get moved into SAL. */ if (is_shub2()) { - xpc_sh2_IPI_access0 = + xpc_sh2_IPI_access0_sn2 = (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS0)); - xpc_sh2_IPI_access1 = + xpc_sh2_IPI_access1_sn2 = (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS1)); - xpc_sh2_IPI_access2 = + xpc_sh2_IPI_access2_sn2 = (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS2)); - xpc_sh2_IPI_access3 = + xpc_sh2_IPI_access3_sn2 = (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS3)); for_each_online_node(node) { @@ -98,7 +98,7 @@ xpc_allow_IPI_ops_sn2(void) -1UL); } } else { - xpc_sh1_IPI_access = + xpc_sh1_IPI_access_sn2 = (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH1_IPI_ACCESS)); for_each_online_node(node) { @@ -123,19 +123,19 @@ xpc_disallow_IPI_ops_sn2(void) for_each_online_node(node) { nasid = cnodeid_to_nasid(node); HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0), - xpc_sh2_IPI_access0); + xpc_sh2_IPI_access0_sn2); HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1), - xpc_sh2_IPI_access1); + xpc_sh2_IPI_access1_sn2); HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2), - xpc_sh2_IPI_access2); + xpc_sh2_IPI_access2_sn2); HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3), - xpc_sh2_IPI_access3); + xpc_sh2_IPI_access3_sn2); } } else { for_each_online_node(node) { nasid = cnodeid_to_nasid(node); HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS), - xpc_sh1_IPI_access); + xpc_sh1_IPI_access_sn2); } } } @@ -182,7 +182,7 @@ xpc_send_IRQ_sn2(struct amo *amo, u64 flag, int nasid, int phys_cpuid, static struct amo * xpc_init_IRQ_amo_sn2(int index) { - struct amo *amo = xpc_vars->amos_page + index; + struct amo *amo = xpc_vars_sn2->amos_page + index; (void)xpc_receive_IRQ_amo_sn2(amo); /* clear amo variable */ return amo; @@ -225,7 +225,7 @@ xpc_send_local_activate_IRQ_sn2(int from_nasid) { int w_index = XPC_NASID_W_INDEX(from_nasid); int b_index = XPC_NASID_B_INDEX(from_nasid); - struct amo *amos = (struct amo *)__va(xpc_vars->amos_page_pa + + struct amo *amos = (struct amo *)__va(xpc_vars_sn2->amos_page_pa + (XPC_ACTIVATE_IRQ_AMOS_SN2 * sizeof(struct amo))); @@ -492,7 +492,8 @@ xpc_indicate_partition_disengaged_sn2(struct xpc_partition *part) static int xpc_partition_engaged_sn2(short partid) { - struct amo *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO_SN2; + struct amo *amo = xpc_vars_sn2->amos_page + + XPC_ENGAGED_PARTITIONS_AMO_SN2; /* our partition's amo variable ANDed with partid mask */ return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & @@ -502,7 +503,8 @@ xpc_partition_engaged_sn2(short partid) static int xpc_any_partition_engaged_sn2(void) { - struct amo *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO_SN2; + struct amo *amo = xpc_vars_sn2->amos_page + + XPC_ENGAGED_PARTITIONS_AMO_SN2; /* our partition's amo variable */ return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) != 0; @@ -511,7 +513,8 @@ xpc_any_partition_engaged_sn2(void) static void xpc_assume_partition_disengaged_sn2(short partid) { - struct amo *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO_SN2; + struct amo *amo = xpc_vars_sn2->amos_page + + XPC_ENGAGED_PARTITIONS_AMO_SN2; /* clear bit(s) based on partid mask in our partition's amo */ FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, @@ -580,27 +583,27 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) int i; int ret; - xpc_vars = XPC_RP_VARS(rp); + xpc_vars_sn2 = XPC_RP_VARS(rp); - rp->sn.vars_pa = __pa(xpc_vars); + rp->sn.vars_pa = __pa(xpc_vars_sn2); /* vars_part array follows immediately after vars */ - xpc_vars_part = (struct xpc_vars_part_sn2 *)((u8 *)XPC_RP_VARS(rp) + - XPC_RP_VARS_SIZE); + xpc_vars_part_sn2 = (struct xpc_vars_part_sn2 *)((u8 *)XPC_RP_VARS(rp) + + XPC_RP_VARS_SIZE); /* - * Before clearing xpc_vars, see if a page of amos had been previously - * allocated. If not we'll need to allocate one and set permissions - * so that cross-partition amos are allowed. + * Before clearing xpc_vars_sn2, see if a page of amos had been + * previously allocated. If not we'll need to allocate one and set + * permissions so that cross-partition amos are allowed. * * The allocated amo page needs MCA reporting to remain disabled after * XPC has unloaded. To make this work, we keep a copy of the pointer - * to this page (i.e., amos_page) in the struct xpc_vars structure, + * to this page (i.e., amos_page) in the struct xpc_vars_sn2 structure, * which is pointed to by the reserved page, and re-use that saved copy * on subsequent loads of XPC. This amo page is never freed, and its * memory protections are never restricted. */ - amos_page = xpc_vars->amos_page; + amos_page = xpc_vars_sn2->amos_page; if (amos_page == NULL) { amos_page = (struct amo *)TO_AMO(uncached_alloc_page(0, 1)); if (amos_page == NULL) { @@ -621,18 +624,18 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) } } - /* clear xpc_vars */ - memset(xpc_vars, 0, sizeof(struct xpc_vars_sn2)); + /* clear xpc_vars_sn2 */ + memset(xpc_vars_sn2, 0, sizeof(struct xpc_vars_sn2)); - xpc_vars->version = XPC_V_VERSION; - xpc_vars->activate_IRQ_nasid = cpuid_to_nasid(0); - xpc_vars->activate_IRQ_phys_cpuid = cpu_physical_id(0); - xpc_vars->vars_part_pa = __pa(xpc_vars_part); - xpc_vars->amos_page_pa = ia64_tpa((u64)amos_page); - xpc_vars->amos_page = amos_page; /* save for next load of XPC */ + xpc_vars_sn2->version = XPC_V_VERSION; + xpc_vars_sn2->activate_IRQ_nasid = cpuid_to_nasid(0); + xpc_vars_sn2->activate_IRQ_phys_cpuid = cpu_physical_id(0); + xpc_vars_sn2->vars_part_pa = __pa(xpc_vars_part_sn2); + xpc_vars_sn2->amos_page_pa = ia64_tpa((u64)amos_page); + xpc_vars_sn2->amos_page = amos_page; /* save for next load of XPC */ - /* clear xpc_vars_part */ - memset((u64 *)xpc_vars_part, 0, sizeof(struct xpc_vars_part_sn2) * + /* clear xpc_vars_part_sn2 */ + memset((u64 *)xpc_vars_part_sn2, 0, sizeof(struct xpc_vars_part_sn2) * xp_max_npartitions); /* initialize the activate IRQ related amo variables */ @@ -649,30 +652,30 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) static void xpc_increment_heartbeat_sn2(void) { - xpc_vars->heartbeat++; + xpc_vars_sn2->heartbeat++; } static void xpc_offline_heartbeat_sn2(void) { xpc_increment_heartbeat_sn2(); - xpc_vars->heartbeat_offline = 1; + xpc_vars_sn2->heartbeat_offline = 1; } static void xpc_online_heartbeat_sn2(void) { xpc_increment_heartbeat_sn2(); - xpc_vars->heartbeat_offline = 0; + xpc_vars_sn2->heartbeat_offline = 0; } static void xpc_heartbeat_init_sn2(void) { - DBUG_ON(xpc_vars == NULL); + DBUG_ON(xpc_vars_sn2 == NULL); - bitmap_zero(xpc_vars->heartbeating_to_mask, XP_MAX_NPARTITIONS_SN2); - xpc_heartbeating_to_mask = &xpc_vars->heartbeating_to_mask[0]; + bitmap_zero(xpc_vars_sn2->heartbeating_to_mask, XP_MAX_NPARTITIONS_SN2); + xpc_heartbeating_to_mask = &xpc_vars_sn2->heartbeating_to_mask[0]; xpc_online_heartbeat_sn2(); } @@ -845,7 +848,8 @@ xpc_cancel_partition_deactivation_request_sn2(struct xpc_partition *part) static int xpc_partition_deactivation_requested_sn2(short partid) { - struct amo *amo = xpc_vars->amos_page + XPC_DEACTIVATE_REQUEST_AMO_SN2; + struct amo *amo = xpc_vars_sn2->amos_page + + XPC_DEACTIVATE_REQUEST_AMO_SN2; /* our partition's amo variable ANDed with partid mask */ return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & @@ -1033,7 +1037,7 @@ xpc_identify_activate_IRQ_sender_sn2(void) int n_IRQs_detected = 0; struct amo *act_amos; - act_amos = xpc_vars->amos_page + XPC_ACTIVATE_IRQ_AMOS_SN2; + act_amos = xpc_vars_sn2->amos_page + XPC_ACTIVATE_IRQ_AMOS_SN2; /* scan through act amo variable looking for non-zero entries */ for (word = 0; word < xpc_nasid_mask_words; word++) { @@ -1261,15 +1265,17 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) * The setting of the magic # indicates that these per partition * specific variables are ready to be used. */ - xpc_vars_part[partid].GPs_pa = __pa(part_sn2->local_GPs); - xpc_vars_part[partid].openclose_args_pa = + xpc_vars_part_sn2[partid].GPs_pa = __pa(part_sn2->local_GPs); + xpc_vars_part_sn2[partid].openclose_args_pa = __pa(part->local_openclose_args); - xpc_vars_part[partid].chctl_amo_pa = __pa(part_sn2->local_chctl_amo_va); + xpc_vars_part_sn2[partid].chctl_amo_pa = + __pa(part_sn2->local_chctl_amo_va); cpuid = raw_smp_processor_id(); /* any CPU in this partition will do */ - xpc_vars_part[partid].notify_IRQ_nasid = cpuid_to_nasid(cpuid); - xpc_vars_part[partid].notify_IRQ_phys_cpuid = cpu_physical_id(cpuid); - xpc_vars_part[partid].nchannels = part->nchannels; - xpc_vars_part[partid].magic = XPC_VP_MAGIC1; + xpc_vars_part_sn2[partid].notify_IRQ_nasid = cpuid_to_nasid(cpuid); + xpc_vars_part_sn2[partid].notify_IRQ_phys_cpuid = + cpu_physical_id(cpuid); + xpc_vars_part_sn2[partid].nchannels = part->nchannels; + xpc_vars_part_sn2[partid].magic = XPC_VP_MAGIC1; return xpSuccess; @@ -1316,7 +1322,7 @@ xpc_teardown_infrastructure_sn2(struct xpc_partition *part) DBUG_ON(part->setup_state != XPC_P_SETUP); part->setup_state = XPC_P_WTEARDOWN; - xpc_vars_part[partid].magic = 0; + xpc_vars_part_sn2[partid].magic = 0; free_irq(SGI_XPC_NOTIFY, (void *)(u64)partid); @@ -1432,7 +1438,7 @@ xpc_pull_remote_vars_part_sn2(struct xpc_partition *part) return xpRetry; } - if (xpc_vars_part[partid].magic == XPC_VP_MAGIC1) { + if (xpc_vars_part_sn2[partid].magic == XPC_VP_MAGIC1) { /* validate the variables */ @@ -1462,7 +1468,7 @@ xpc_pull_remote_vars_part_sn2(struct xpc_partition *part) /* let the other side know that we've pulled their variables */ - xpc_vars_part[partid].magic = XPC_VP_MAGIC2; + xpc_vars_part_sn2[partid].magic = XPC_VP_MAGIC2; } if (pulled_entry->magic == XPC_VP_MAGIC1) -- cgit v1.2.3 From ea57f80c8c0e59cfc5095f7e856ce7c8e6ac2984 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:14 -0700 Subject: sgi-xp: eliminate '>>>' in comments Comments in /drivers/misc/sgi-xp has been using '>>>' as a means to draw attention to something that needs to be done or considered. To avoid colliding with git rejects, '>>>' will now be replaced by '!!!' to indicate something to do, and by '???' to indicate something to be considered. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xp.h | 11 +++-------- drivers/misc/sgi-xp/xp_sn2.c | 10 +++++----- drivers/misc/sgi-xp/xp_uv.c | 2 +- drivers/misc/sgi-xp/xpc.h | 14 +++++++++----- drivers/misc/sgi-xp/xpc_channel.c | 2 +- drivers/misc/sgi-xp/xpc_partition.c | 2 +- drivers/misc/sgi-xp/xpc_sn2.c | 8 ++++---- drivers/misc/sgi-xp/xpc_uv.c | 32 ++++++++++++++++---------------- drivers/misc/sgi-xp/xpnet.c | 6 +++--- 9 files changed, 43 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index 955b5b91323..0ca81f16646 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -21,7 +21,7 @@ #include #endif -/* >>> Add this #define to some linux header file some day. */ +/* ??? Add this #define to some linux header file some day? */ #define BYTES_PER_WORD sizeof(void *) #ifdef USE_DBUG_ON @@ -65,18 +65,13 @@ * other partition that is currently up. Over these channels, kernel-level * `users' can communicate with their counterparts on the other partitions. * ->>> The following described limitation of a max of eight channels possible ->>> pertains only to ia64-sn2. THIS ISN'T TRUE SINCE I'M PLANNING TO JUST ->>> TIE INTO THE EXISTING MECHANISM ONCE THE CHANNEL MESSAGES ARE RECEIVED. ->>> THE 128-BYTE CACHELINE PERFORMANCE ISSUE IS TIED TO IA64-SN2. - * * If the need for additional channels arises, one can simply increase * XPC_MAX_NCHANNELS accordingly. If the day should come where that number * exceeds the absolute MAXIMUM number of channels possible (eight), then one * will need to make changes to the XPC code to accommodate for this. * - * The absolute maximum number of channels possible is currently limited to - * eight for performance reasons. The internal cross partition structures + * The absolute maximum number of channels possible is limited to eight for + * performance reasons on sn2 hardware. The internal cross partition structures * require sixteen bytes per channel, and eight allows all of this * interface-shared info to fit in one 128-byte cacheline. */ diff --git a/drivers/misc/sgi-xp/xp_sn2.c b/drivers/misc/sgi-xp/xp_sn2.c index 1fcfdebca2c..baabc1cb3fe 100644 --- a/drivers/misc/sgi-xp/xp_sn2.c +++ b/drivers/misc/sgi-xp/xp_sn2.c @@ -87,11 +87,11 @@ xp_remote_memcpy_sn2(void *vdst, const void *psrc, size_t len) { bte_result_t ret; u64 pdst = ia64_tpa(vdst); - /* >>> What are the rules governing the src and dst addresses passed in? - * >>> Currently we're assuming that dst is a virtual address and src - * >>> is a physical address, is this appropriate? Can we allow them to - * >>> be whatever and we make the change here without damaging the - * >>> addresses? + /* ??? What are the rules governing the src and dst addresses passed in? + * ??? Currently we're assuming that dst is a virtual address and src + * ??? is a physical address, is this appropriate? Can we allow them to + * ??? be whatever and we make the change here without damaging the + * ??? addresses? */ /* diff --git a/drivers/misc/sgi-xp/xp_uv.c b/drivers/misc/sgi-xp/xp_uv.c index dca519fdef9..382b1b6bcc0 100644 --- a/drivers/misc/sgi-xp/xp_uv.c +++ b/drivers/misc/sgi-xp/xp_uv.c @@ -18,7 +18,7 @@ static enum xp_retval xp_remote_memcpy_uv(void *vdst, const void *psrc, size_t len) { - /* >>> this function needs fleshing out */ + /* !!! this function needs fleshing out */ return xpUnsupported; } diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 2111723553b..0f516c3e3e6 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -276,9 +276,12 @@ struct xpc_notify { * There is an array of these structures for each remote partition. It is * allocated at the time a partition becomes active. The array contains one * of these structures for each potential channel connection to that partition. + */ + +/* + * The following is sn2 only. * ->>> sn2 only!!! - * Each of these structures manages two message queues (circular buffers). + * Each channel structure manages two message queues (circular buffers). * They are allocated at the time a channel connection is made. One of * these message queues (local_msgqueue) holds the locally created messages * that are destined for the remote partition. The other of these message @@ -345,6 +348,7 @@ struct xpc_notify { * new messages, by the clearing of the message flags of the acknowledged * messages. */ + struct xpc_channel_sn2 { /* various flavors of local and remote Get/Put values */ @@ -359,7 +363,7 @@ struct xpc_channel_sn2 { }; struct xpc_channel_uv { - /* >>> code is coming */ + /* !!! code is coming */ }; struct xpc_channel { @@ -500,7 +504,7 @@ xpc_any_msg_chctl_flags_set(union xpc_channel_ctl_flags *chctl) } /* - * Manages channels on a partition basis. There is one of these structures + * Manage channels on a partition basis. There is one of these structures * for each partition (a partition will never utilize the structure that * represents itself). */ @@ -535,7 +539,7 @@ struct xpc_partition_sn2 { }; struct xpc_partition_uv { - /* >>> code is coming */ + /* !!! code is coming */ }; struct xpc_partition { diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index 1c73423665b..f1afc0a7c33 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -129,7 +129,7 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) /* wake those waiting for notify completion */ if (atomic_read(&ch->n_to_notify) > 0) { - /* >>> we do callout while holding ch->lock */ + /* we do callout while holding ch->lock, callout can't block */ xpc_notify_senders_of_disconnect(ch); } diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 9f104450478..73a92957b80 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -91,7 +91,7 @@ xpc_get_rsvd_page_pa(int nasid) if (status != SALRET_MORE_PASSES) break; - /* >>> L1_CACHE_ALIGN() is only a sn2-bte_copy requirement */ + /* !!! L1_CACHE_ALIGN() is only a sn2-bte_copy requirement */ if (L1_CACHE_ALIGN(len) > buf_len) { kfree(buf_base); buf_len = L1_CACHE_ALIGN(len); diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index 63fe59a5bfa..e42c3038203 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -75,7 +75,7 @@ xpc_allow_IPI_ops_sn2(void) int node; int nasid; - /* >>> The following should get moved into SAL. */ + /* !!! The following should get moved into SAL. */ if (is_shub2()) { xpc_sh2_IPI_access0_sn2 = (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS0)); @@ -118,7 +118,7 @@ xpc_disallow_IPI_ops_sn2(void) int node; int nasid; - /* >>> The following should get moved into SAL. */ + /* !!! The following should get moved into SAL. */ if (is_shub2()) { for_each_online_node(node) { nasid = cnodeid_to_nasid(node); @@ -1360,7 +1360,7 @@ xpc_teardown_infrastructure_sn2(struct xpc_partition *part) * dst must be a cacheline aligned virtual address on this partition. * cnt must be cacheline sized */ -/* >>> Replace this function by call to xp_remote_memcpy() or bte_copy()? */ +/* ??? Replace this function by call to xp_remote_memcpy() or bte_copy()? */ static enum xp_retval xpc_pull_remote_cachelines_sn2(struct xpc_partition *part, void *dst, const void *src, size_t cnt) @@ -2242,7 +2242,7 @@ xpc_send_msg_sn2(struct xpc_channel *ch, u32 flags, void *payload, notify->key = key; notify->type = notify_type; - /* >>> is a mb() needed here? */ + /* ??? Is a mb() needed here? */ if (ch->flags & XPC_C_DISCONNECTING) { /* diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index 1401b0f45dc..2aec1dfbb3d 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c @@ -15,8 +15,8 @@ #include -/* >>> #include */ -/* >>> uv_gpa() is defined in */ +/* !!! #include */ +/* !!! uv_gpa() is defined in */ #define uv_gpa(_a) ((unsigned long)_a) #include "xpc.h" @@ -29,16 +29,16 @@ static void xpc_send_local_activate_IRQ_uv(struct xpc_partition *part) { /* - * >>> make our side think that the remote parition sent an activate - * >>> message our way. Also do what the activate IRQ handler would - * >>> do had one really been sent. + * !!! Make our side think that the remote parition sent an activate + * !!! message our way. Also do what the activate IRQ handler would + * !!! do had one really been sent. */ } static enum xp_retval xpc_rsvd_page_init_uv(struct xpc_rsvd_page *rp) { - /* >>> need to have established xpc_activate_mq earlier */ + /* !!! need to have established xpc_activate_mq earlier */ rp->sn.activate_mq_gpa = uv_gpa(xpc_activate_mq); return xpSuccess; } @@ -46,7 +46,7 @@ xpc_rsvd_page_init_uv(struct xpc_rsvd_page *rp) static void xpc_increment_heartbeat_uv(void) { - /* >>> send heartbeat msg to xpc_heartbeating_to_mask partids */ + /* !!! send heartbeat msg to xpc_heartbeating_to_mask partids */ } static void @@ -59,7 +59,7 @@ xpc_heartbeat_init_uv(void) static void xpc_heartbeat_exit_uv(void) { - /* >>> send heartbeat_offline msg to xpc_heartbeating_to_mask partids */ + /* !!! send heartbeat_offline msg to xpc_heartbeating_to_mask partids */ } static void @@ -70,9 +70,9 @@ xpc_request_partition_activation_uv(struct xpc_rsvd_page *remote_rp, struct xpc_partition *part = &xpc_partitions[partid]; /* - * >>> setup part structure with the bits of info we can glean from the rp - * >>> part->remote_rp_pa = remote_rp_pa; - * >>> part->sn.uv.activate_mq_gpa = remote_rp->sn.activate_mq_gpa; + * !!! Setup part structure with the bits of info we can glean from the rp: + * !!! part->remote_rp_pa = remote_rp_pa; + * !!! part->sn.uv.activate_mq_gpa = remote_rp->sn.activate_mq_gpa; */ xpc_send_local_activate_IRQ_uv(part); @@ -91,7 +91,7 @@ xpc_request_partition_reactivation_uv(struct xpc_partition *part) static enum xp_retval xpc_setup_infrastructure_uv(struct xpc_partition *part) { - /* >>> this function needs fleshing out */ + /* !!! this function needs fleshing out */ return xpUnsupported; } @@ -102,28 +102,28 @@ xpc_setup_infrastructure_uv(struct xpc_partition *part) static void xpc_teardown_infrastructure_uv(struct xpc_partition *part) { - /* >>> this function needs fleshing out */ + /* !!! this function needs fleshing out */ return; } static enum xp_retval xpc_make_first_contact_uv(struct xpc_partition *part) { - /* >>> this function needs fleshing out */ + /* !!! this function needs fleshing out */ return xpUnsupported; } static u64 xpc_get_chctl_all_flags_uv(struct xpc_partition *part) { - /* >>> this function needs fleshing out */ + /* !!! this function needs fleshing out */ return 0UL; } static struct xpc_msg * xpc_get_deliverable_msg_uv(struct xpc_channel *ch) { - /* >>> this function needs fleshing out */ + /* !!! this function needs fleshing out */ return NULL; } diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index c5f59a6dae5..07c89c4e2c2 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -229,9 +229,9 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) if (ret != xpSuccess) { /* - * >>> Need better way of cleaning skb. Currently skb - * >>> appears in_use and we can't just call - * >>> dev_kfree_skb. + * !!! Need better way of cleaning skb. Currently skb + * !!! appears in_use and we can't just call + * !!! dev_kfree_skb. */ dev_err(xpnet, "xp_remote_memcpy(0x%p, 0x%p, 0x%hx) " "returned error=0x%x\n", (void *) -- cgit v1.2.3 From 04de741885bc7565a28150e82c56a56e544440e6 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:14 -0700 Subject: sgi-xp: use standard bitops macros and functions Change sgi-xp to use the standard bitops macros and functions instead of trying to invent its own mechanism. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xp.h | 3 -- drivers/misc/sgi-xp/xpc.h | 43 ++++++++-------------- drivers/misc/sgi-xp/xpc_partition.c | 43 +++++++++++----------- drivers/misc/sgi-xp/xpc_sn2.c | 73 ++++++++++++++++++++----------------- 4 files changed, 76 insertions(+), 86 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index 0ca81f16646..3054fae8b02 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -21,9 +21,6 @@ #include #endif -/* ??? Add this #define to some linux header file some day? */ -#define BYTES_PER_WORD sizeof(void *) - #ifdef USE_DBUG_ON #define DBUG_ON(condition) BUG_ON(condition) #else diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 0f516c3e3e6..0907934cdd8 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -35,23 +35,7 @@ #define XPC_VERSION_MAJOR(_v) ((_v) >> 4) #define XPC_VERSION_MINOR(_v) ((_v) & 0xf) -/* - * The next macros define word or bit representations for given - * C-brick nasid in either the SAL provided bit array representing - * nasids in the partition/machine or the array of amo structures used - * for inter-partition initiation communications. - * - * For SN2 machines, C-Bricks are alway even numbered NASIDs. As - * such, some space will be saved by insisting that nasid information - * passed from SAL always be packed for C-Bricks and the - * cross-partition interrupts use the same packing scheme. - */ -#define XPC_NASID_W_INDEX(_n) (((_n) / 64) / 2) -#define XPC_NASID_B_INDEX(_n) (((_n) / 2) & (64 - 1)) -#define XPC_NASID_IN_ARRAY(_n, _p) ((_p)[XPC_NASID_W_INDEX(_n)] & \ - (1UL << XPC_NASID_B_INDEX(_n))) -#define XPC_NASID_FROM_W_B(_w, _b) (((_w) * 64 + (_b)) * 2) - +/* define frequency of the heartbeat and frequency how often it's checked */ #define XPC_HB_DEFAULT_INTERVAL 5 /* incr HB every x secs */ #define XPC_HB_CHECK_DEFAULT_INTERVAL 20 /* check HB every x secs */ @@ -86,11 +70,13 @@ * the actual nasids in the entire machine (mach_nasids). We're only * interested in the even numbered nasids (which contain the processors * and/or memory), so we only need half as many bits to represent the - * nasids. The part_nasids mask is located starting at the first cacheline - * following the reserved page header. The mach_nasids mask follows right - * after the part_nasids mask. The size in bytes of each mask is reflected - * by the reserved page header field 'SAL_nasids_size'. (Local partition's - * mask pointers are xpc_part_nasids and xpc_mach_nasids.) + * nasids. When mapping nasid to bit in a mask (or bit to nasid) be sure + * to either divide or multiply by 2. The part_nasids mask is located + * starting at the first cacheline following the reserved page header. The + * mach_nasids mask follows right after the part_nasids mask. The size in + * bytes of each mask is reflected by the reserved page header field + * 'SAL_nasids_size'. (Local partition's mask pointers are xpc_part_nasids + * and xpc_mach_nasids.) * * vars (ia64-sn2 only) * vars part (ia64-sn2 only) @@ -194,10 +180,11 @@ struct xpc_vars_part_sn2 { #define XPC_RP_VARS_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_vars_sn2)) #define XPC_RP_PART_NASIDS(_rp) ((u64 *)((u8 *)(_rp) + XPC_RP_HEADER_SIZE)) -#define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + xpc_nasid_mask_words) +#define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + \ + xpc_nasid_mask_nlongs) #define XPC_RP_VARS(_rp) ((struct xpc_vars_sn2 *) \ (XPC_RP_MACH_NASIDS(_rp) + \ - xpc_nasid_mask_words)) + xpc_nasid_mask_nlongs)) /* * Functions registered by add_timer() or called by kernel_thread() only @@ -695,9 +682,9 @@ extern void xpc_exit_uv(void); /* found in xpc_partition.c */ extern int xpc_exiting; -extern int xpc_nasid_mask_words; +extern int xpc_nasid_mask_nlongs; extern struct xpc_rsvd_page *xpc_rsvd_page; -extern u64 *xpc_mach_nasids; +extern unsigned long *xpc_mach_nasids; extern struct xpc_partition *xpc_partitions; extern void *xpc_kmalloc_cacheline_aligned(size_t, gfp_t, void **); extern struct xpc_rsvd_page *xpc_setup_rsvd_page(void); @@ -706,8 +693,8 @@ extern int xpc_partition_disengaged(struct xpc_partition *); extern enum xp_retval xpc_mark_partition_active(struct xpc_partition *); extern void xpc_mark_partition_inactive(struct xpc_partition *); extern void xpc_discovery(void); -extern enum xp_retval xpc_get_remote_rp(int, u64 *, struct xpc_rsvd_page *, - u64 *); +extern enum xp_retval xpc_get_remote_rp(int, unsigned long *, + struct xpc_rsvd_page *, u64 *); extern void xpc_deactivate_partition(const int, struct xpc_partition *, enum xp_retval); extern enum xp_retval xpc_initiate_partid_to_nasids(short, void *); diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 73a92957b80..ca6784f5597 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -31,11 +31,11 @@ int xpc_exiting; /* this partition's reserved page pointers */ struct xpc_rsvd_page *xpc_rsvd_page; -static u64 *xpc_part_nasids; -u64 *xpc_mach_nasids; +static unsigned long *xpc_part_nasids; +unsigned long *xpc_mach_nasids; -static int xpc_sizeof_nasid_mask; /* actual size in bytes of nasid mask */ -int xpc_nasid_mask_words; /* actual size in words of nasid mask */ +static int xpc_nasid_mask_nbytes; /* #of bytes in nasid mask */ +int xpc_nasid_mask_nlongs; /* #of longs in nasid mask */ struct xpc_partition *xpc_partitions; @@ -167,9 +167,9 @@ xpc_setup_rsvd_page(void) /* SAL_version 1 didn't set the nasids_size field */ rp->SAL_nasids_size = 128; } - xpc_sizeof_nasid_mask = rp->SAL_nasids_size; - xpc_nasid_mask_words = DIV_ROUND_UP(xpc_sizeof_nasid_mask, - BYTES_PER_WORD); + xpc_nasid_mask_nbytes = rp->SAL_nasids_size; + xpc_nasid_mask_nlongs = BITS_TO_LONGS(rp->SAL_nasids_size * + BITS_PER_BYTE); /* setup the pointers to the various items in the reserved page */ xpc_part_nasids = XPC_RP_PART_NASIDS(rp); @@ -199,10 +199,10 @@ xpc_setup_rsvd_page(void) * part_nasids mask. */ enum xp_retval -xpc_get_remote_rp(int nasid, u64 *discovered_nasids, +xpc_get_remote_rp(int nasid, unsigned long *discovered_nasids, struct xpc_rsvd_page *remote_rp, u64 *remote_rp_pa) { - int i; + int l; enum xp_retval ret; /* get the reserved page's physical address */ @@ -213,15 +213,16 @@ xpc_get_remote_rp(int nasid, u64 *discovered_nasids, /* pull over the reserved page header and part_nasids mask */ ret = xp_remote_memcpy(remote_rp, (void *)*remote_rp_pa, - XPC_RP_HEADER_SIZE + xpc_sizeof_nasid_mask); + XPC_RP_HEADER_SIZE + xpc_nasid_mask_nbytes); if (ret != xpSuccess) return ret; if (discovered_nasids != NULL) { - u64 *remote_part_nasids = XPC_RP_PART_NASIDS(remote_rp); + unsigned long *remote_part_nasids = + XPC_RP_PART_NASIDS(remote_rp); - for (i = 0; i < xpc_nasid_mask_words; i++) - discovered_nasids[i] |= remote_part_nasids[i]; + for (l = 0; l < xpc_nasid_mask_nlongs; l++) + discovered_nasids[l] |= remote_part_nasids[l]; } /* see if the reserved page has been set up by XPC */ @@ -401,16 +402,16 @@ xpc_discovery(void) int max_regions; int nasid; struct xpc_rsvd_page *rp; - u64 *discovered_nasids; + unsigned long *discovered_nasids; enum xp_retval ret; remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE + - xpc_sizeof_nasid_mask, + xpc_nasid_mask_nbytes, GFP_KERNEL, &remote_rp_base); if (remote_rp == NULL) return; - discovered_nasids = kzalloc(sizeof(u64) * xpc_nasid_mask_words, + discovered_nasids = kzalloc(sizeof(long) * xpc_nasid_mask_nlongs, GFP_KERNEL); if (discovered_nasids == NULL) { kfree(remote_rp_base); @@ -453,21 +454,21 @@ xpc_discovery(void) dev_dbg(xpc_part, "checking nasid %d\n", nasid); - if (XPC_NASID_IN_ARRAY(nasid, xpc_part_nasids)) { + if (test_bit(nasid / 2, xpc_part_nasids)) { dev_dbg(xpc_part, "PROM indicates Nasid %d is " "part of the local partition; skipping " "region\n", nasid); break; } - if (!(XPC_NASID_IN_ARRAY(nasid, xpc_mach_nasids))) { + if (!(test_bit(nasid / 2, xpc_mach_nasids))) { dev_dbg(xpc_part, "PROM indicates Nasid %d was " "not on Numa-Link network at reset\n", nasid); continue; } - if (XPC_NASID_IN_ARRAY(nasid, discovered_nasids)) { + if (test_bit(nasid / 2, discovered_nasids)) { dev_dbg(xpc_part, "Nasid %d is part of a " "partition which was previously " "discovered\n", nasid); @@ -512,10 +513,10 @@ xpc_initiate_partid_to_nasids(short partid, void *nasid_mask) if (part->remote_rp_pa == 0) return xpPartitionDown; - memset(nasid_mask, 0, xpc_sizeof_nasid_mask); + memset(nasid_mask, 0, xpc_nasid_mask_nbytes); part_nasid_pa = (u64)XPC_RP_PART_NASIDS(part->remote_rp_pa); return xp_remote_memcpy(nasid_mask, (void *)part_nasid_pa, - xpc_sizeof_nasid_mask); + xpc_nasid_mask_nbytes); } diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index e42c3038203..f82889f6015 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -210,28 +210,26 @@ static void xpc_send_activate_IRQ_sn2(u64 amos_page_pa, int from_nasid, int to_nasid, int to_phys_cpuid) { - int w_index = XPC_NASID_W_INDEX(from_nasid); - int b_index = XPC_NASID_B_INDEX(from_nasid); struct amo *amos = (struct amo *)__va(amos_page_pa + (XPC_ACTIVATE_IRQ_AMOS_SN2 * sizeof(struct amo))); - (void)xpc_send_IRQ_sn2(&amos[w_index], (1UL << b_index), to_nasid, + (void)xpc_send_IRQ_sn2(&amos[BIT_WORD(from_nasid / 2)], + BIT_MASK(from_nasid / 2), to_nasid, to_phys_cpuid, SGI_XPC_ACTIVATE); } static void xpc_send_local_activate_IRQ_sn2(int from_nasid) { - int w_index = XPC_NASID_W_INDEX(from_nasid); - int b_index = XPC_NASID_B_INDEX(from_nasid); struct amo *amos = (struct amo *)__va(xpc_vars_sn2->amos_page_pa + (XPC_ACTIVATE_IRQ_AMOS_SN2 * sizeof(struct amo))); /* fake the sending and receipt of an activate IRQ from remote nasid */ - FETCHOP_STORE_OP(TO_AMO((u64)&amos[w_index].variable), FETCHOP_OR, - (1UL << b_index)); + FETCHOP_STORE_OP(TO_AMO((u64)&amos[BIT_WORD(from_nasid / 2)].variable), + FETCHOP_OR, BIT_MASK(from_nasid / 2)); + atomic_inc(&xpc_activate_IRQ_rcvd); wake_up_interruptible(&xpc_activate_IRQ_wq); } @@ -439,7 +437,8 @@ xpc_indicate_partition_engaged_sn2(struct xpc_partition *part) /* set bit corresponding to our partid in remote partition's amo */ FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, - (1UL << sn_partition_id)); + BIT(sn_partition_id)); + /* * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we @@ -466,7 +465,8 @@ xpc_indicate_partition_disengaged_sn2(struct xpc_partition *part) /* clear bit corresponding to our partid in remote partition's amo */ FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, - ~(1UL << sn_partition_id)); + ~BIT(sn_partition_id)); + /* * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we @@ -497,7 +497,7 @@ xpc_partition_engaged_sn2(short partid) /* our partition's amo variable ANDed with partid mask */ return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & - (1UL << partid)) != 0; + BIT(partid)) != 0; } static int @@ -518,7 +518,7 @@ xpc_assume_partition_disengaged_sn2(short partid) /* clear bit(s) based on partid mask in our partition's amo */ FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, - ~(1UL << partid)); + ~BIT(partid)); } /* original protection values for each node */ @@ -639,7 +639,7 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) xp_max_npartitions); /* initialize the activate IRQ related amo variables */ - for (i = 0; i < xpc_nasid_mask_words; i++) + for (i = 0; i < xpc_nasid_mask_nlongs; i++) (void)xpc_init_IRQ_amo_sn2(XPC_ACTIVATE_IRQ_AMOS_SN2 + i); /* initialize the engaged remote partitions related amo variables */ @@ -796,7 +796,8 @@ xpc_request_partition_deactivation_sn2(struct xpc_partition *part) /* set bit corresponding to our partid in remote partition's amo */ FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, - (1UL << sn_partition_id)); + BIT(sn_partition_id)); + /* * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we @@ -831,7 +832,8 @@ xpc_cancel_partition_deactivation_request_sn2(struct xpc_partition *part) /* clear bit corresponding to our partid in remote partition's amo */ FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, - ~(1UL << sn_partition_id)); + ~BIT(sn_partition_id)); + /* * We must always use the nofault function regardless of whether we * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we @@ -853,7 +855,7 @@ xpc_partition_deactivation_requested_sn2(short partid) /* our partition's amo variable ANDed with partid mask */ return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) & - (1UL << partid)) != 0; + BIT(partid)) != 0; } /* @@ -1031,28 +1033,31 @@ xpc_identify_activate_IRQ_req_sn2(int nasid) int xpc_identify_activate_IRQ_sender_sn2(void) { - int word, bit; - u64 nasid_mask; + int l; + int b; + unsigned long nasid_mask_long; u64 nasid; /* remote nasid */ int n_IRQs_detected = 0; struct amo *act_amos; act_amos = xpc_vars_sn2->amos_page + XPC_ACTIVATE_IRQ_AMOS_SN2; - /* scan through act amo variable looking for non-zero entries */ - for (word = 0; word < xpc_nasid_mask_words; word++) { + /* scan through activate amo variables looking for non-zero entries */ + for (l = 0; l < xpc_nasid_mask_nlongs; l++) { if (xpc_exiting) break; - nasid_mask = xpc_receive_IRQ_amo_sn2(&act_amos[word]); - if (nasid_mask == 0) { - /* no IRQs from nasids in this variable */ + nasid_mask_long = xpc_receive_IRQ_amo_sn2(&act_amos[l]); + + b = find_first_bit(&nasid_mask_long, BITS_PER_LONG); + if (b >= BITS_PER_LONG) { + /* no IRQs from nasids in this amo variable */ continue; } - dev_dbg(xpc_part, "amo[%d] gave back 0x%lx\n", word, - nasid_mask); + dev_dbg(xpc_part, "amo[%d] gave back 0x%lx\n", l, + nasid_mask_long); /* * If this nasid has been added to the machine since @@ -1060,19 +1065,19 @@ xpc_identify_activate_IRQ_sender_sn2(void) * remote nasid in our reserved pages machine mask. * This is used in the event of module reload. */ - xpc_mach_nasids[word] |= nasid_mask; + xpc_mach_nasids[l] |= nasid_mask_long; /* locate the nasid(s) which sent interrupts */ - for (bit = 0; bit < (8 * sizeof(u64)); bit++) { - if (nasid_mask & (1UL << bit)) { - n_IRQs_detected++; - nasid = XPC_NASID_FROM_W_B(word, bit); - dev_dbg(xpc_part, "interrupt from nasid %ld\n", - nasid); - xpc_identify_activate_IRQ_req_sn2(nasid); - } - } + do { + n_IRQs_detected++; + nasid = (l * BITS_PER_LONG + b) * 2; + dev_dbg(xpc_part, "interrupt from nasid %ld\n", nasid); + xpc_identify_activate_IRQ_req_sn2(nasid); + + b = find_next_bit(&nasid_mask_long, BITS_PER_LONG, + b + 1); + } while (b < BITS_PER_LONG); } return n_IRQs_detected; } -- cgit v1.2.3 From 81fe7883d2c8a80a7145ad22f8cd8514d05412b9 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:15 -0700 Subject: sgi-xp: add 'jiffies' to reserved page's timestamp name Rename XPC's reserved page's timestamp member to reflect the units of time involved. Signed-off-by: Dean Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xpc.h | 6 +++--- drivers/misc/sgi-xp/xpc_main.c | 8 ++++---- drivers/misc/sgi-xp/xpc_partition.c | 14 +++++++------- drivers/misc/sgi-xp/xpc_sn2.c | 26 ++++++++++++++------------ 4 files changed, 28 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 0907934cdd8..e194d3140f6 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -87,7 +87,7 @@ * which are partition specific (vars part). These are setup by XPC. * (Local partition's vars pointers are xpc_vars and xpc_vars_part.) * - * Note: Until 'stamp' is set non-zero, the partition XPC code has not been + * Note: Until 'ts_jiffies' is set non-zero, the partition XPC code has not been * initialized. */ struct xpc_rsvd_page { @@ -101,7 +101,7 @@ struct xpc_rsvd_page { u64 vars_pa; /* physical address of struct xpc_vars */ u64 activate_mq_gpa; /* global phys address of activate_mq */ } sn; - unsigned long stamp; /* time when reserved page was setup by XPC */ + unsigned long ts_jiffies; /* timestamp when rsvd pg was setup by XPC */ u64 pad2[10]; /* align to last u64 in 2nd 64-byte cacheline */ u64 SAL_nasids_size; /* SAL: size of each nasid mask in bytes */ }; @@ -534,7 +534,7 @@ struct xpc_partition { /* XPC HB infrastructure */ u8 remote_rp_version; /* version# of partition's rsvd pg */ - unsigned long remote_rp_stamp; /* time when rsvd pg was initialized */ + unsigned long remote_rp_ts_jiffies; /* timestamp when rsvd pg setup */ u64 remote_rp_pa; /* phys addr of partition's rsvd pg */ u64 last_heartbeat; /* HB at last read */ u32 activate_IRQ_rcvd; /* IRQs since activation */ diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index 36dfccea524..e7ff9e1670f 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -862,8 +862,8 @@ xpc_do_exit(enum xp_retval reason) DBUG_ON(xpc_any_partition_engaged()); DBUG_ON(xpc_any_hbs_allowed() != 0); - /* indicate to others that our reserved page is uninitialized */ - xpc_rsvd_page->stamp = 0; + /* a zero timestamp indicates our rsvd page is not initialized */ + xpc_rsvd_page->ts_jiffies = 0; if (reason == xpUnloading) { (void)unregister_die_notifier(&xpc_die_notifier); @@ -1152,8 +1152,8 @@ xpc_init(void) /* initialization was not successful */ out_3: - /* indicate to others that our reserved page is uninitialized */ - xpc_rsvd_page->stamp = 0; + /* a zero timestamp indicates our rsvd page is not initialized */ + xpc_rsvd_page->ts_jiffies = 0; (void)unregister_die_notifier(&xpc_die_notifier); (void)unregister_reboot_notifier(&xpc_reboot_notifier); diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index ca6784f5597..70d4a00c972 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -133,7 +133,7 @@ xpc_setup_rsvd_page(void) { struct xpc_rsvd_page *rp; u64 rp_pa; - unsigned long new_stamp; + unsigned long new_ts_jiffies; /* get the local reserved page's address */ @@ -183,10 +183,10 @@ xpc_setup_rsvd_page(void) * This signifies to the remote partition that our reserved * page is initialized. */ - new_stamp = jiffies; - if (new_stamp == 0 || new_stamp == rp->stamp) - new_stamp++; - rp->stamp = new_stamp; + new_ts_jiffies = jiffies; + if (new_ts_jiffies == 0 || new_ts_jiffies == rp->ts_jiffies) + new_ts_jiffies++; + rp->ts_jiffies = new_ts_jiffies; return rp; } @@ -225,8 +225,8 @@ xpc_get_remote_rp(int nasid, unsigned long *discovered_nasids, discovered_nasids[l] |= remote_part_nasids[l]; } - /* see if the reserved page has been set up by XPC */ - if (remote_rp->stamp == 0) + /* zero timestamp indicates the reserved page has not been setup */ + if (remote_rp->ts_jiffies == 0) return xpRsvdPageNotSet; if (XPC_VERSION_MAJOR(remote_rp->version) != diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index f82889f6015..4b5f69edf0d 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -863,8 +863,8 @@ xpc_partition_deactivation_requested_sn2(short partid) */ static void xpc_update_partition_info_sn2(struct xpc_partition *part, u8 remote_rp_version, - unsigned long *remote_rp_stamp, u64 remote_rp_pa, - u64 remote_vars_pa, + unsigned long *remote_rp_ts_jiffies, + u64 remote_rp_pa, u64 remote_vars_pa, struct xpc_vars_sn2 *remote_vars) { struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; @@ -873,9 +873,9 @@ xpc_update_partition_info_sn2(struct xpc_partition *part, u8 remote_rp_version, dev_dbg(xpc_part, " remote_rp_version = 0x%016x\n", part->remote_rp_version); - part->remote_rp_stamp = *remote_rp_stamp; - dev_dbg(xpc_part, " remote_rp_stamp = 0x%016lx\n", - part->remote_rp_stamp); + part->remote_rp_ts_jiffies = *remote_rp_ts_jiffies; + dev_dbg(xpc_part, " remote_rp_ts_jiffies = 0x%016lx\n", + part->remote_rp_ts_jiffies); part->remote_rp_pa = remote_rp_pa; dev_dbg(xpc_part, " remote_rp_pa = 0x%016lx\n", part->remote_rp_pa); @@ -933,7 +933,7 @@ xpc_identify_activate_IRQ_req_sn2(int nasid) u64 remote_vars_pa; int remote_rp_version; int reactivate = 0; - unsigned long remote_rp_stamp = 0; + unsigned long remote_rp_ts_jiffies = 0; short partid; struct xpc_partition *part; struct xpc_partition_sn2 *part_sn2; @@ -952,7 +952,7 @@ xpc_identify_activate_IRQ_req_sn2(int nasid) remote_vars_pa = remote_rp->sn.vars_pa; remote_rp_version = remote_rp->version; - remote_rp_stamp = remote_rp->stamp; + remote_rp_ts_jiffies = remote_rp->ts_jiffies; partid = remote_rp->SAL_partid; part = &xpc_partitions[partid]; @@ -981,8 +981,9 @@ xpc_identify_activate_IRQ_req_sn2(int nasid) part->act_state == XPC_P_INACTIVE) { xpc_update_partition_info_sn2(part, remote_rp_version, - &remote_rp_stamp, remote_rp_pa, - remote_vars_pa, remote_vars); + &remote_rp_ts_jiffies, + remote_rp_pa, remote_vars_pa, + remote_vars); if (xpc_partition_deactivation_requested_sn2(partid)) { /* @@ -999,7 +1000,7 @@ xpc_identify_activate_IRQ_req_sn2(int nasid) DBUG_ON(part->remote_rp_version == 0); DBUG_ON(part_sn2->remote_vars_version == 0); - if (remote_rp_stamp != part->remote_rp_stamp) { + if (remote_rp_ts_jiffies != part->remote_rp_ts_jiffies) { /* the other side rebooted */ @@ -1007,8 +1008,9 @@ xpc_identify_activate_IRQ_req_sn2(int nasid) DBUG_ON(xpc_partition_deactivation_requested_sn2(partid)); xpc_update_partition_info_sn2(part, remote_rp_version, - &remote_rp_stamp, remote_rp_pa, - remote_vars_pa, remote_vars); + &remote_rp_ts_jiffies, + remote_rp_pa, remote_vars_pa, + remote_vars); reactivate = 1; } -- cgit v1.2.3 From 261f3b4979db88d29fc86aad9f76fbc0c2c6d21a Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:16 -0700 Subject: sgi-xp: enable building of XPC/XPNET on x86_64 Get XPC/XPNET to build on x86_64. Trying to modprobe them up on a non-UV or sn2 system will result in a -ENODEV. Signed-off-by: Dean Nelson Cc: Jack Steiner Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/Kconfig | 2 +- drivers/misc/sgi-xp/Makefile | 14 ++++++++--- drivers/misc/sgi-xp/xp.h | 32 +++++++++++++++--------- drivers/misc/sgi-xp/xp_main.c | 10 +++++++- drivers/misc/sgi-xp/xp_sn2.c | 10 ++++++++ drivers/misc/sgi-xp/xpc.h | 34 ++++++++++++------------- drivers/misc/sgi-xp/xpc_channel.c | 18 +++++--------- drivers/misc/sgi-xp/xpc_main.c | 49 +++++++++++++++++++------------------ drivers/misc/sgi-xp/xpc_partition.c | 47 +++++++++++++++-------------------- drivers/misc/sgi-xp/xpc_sn2.c | 30 +++++++++++++++++++---- drivers/misc/sgi-xp/xpc_uv.c | 7 ++---- drivers/misc/sgi-xp/xpnet.c | 28 +++++++++------------ 12 files changed, 155 insertions(+), 126 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 4b288f43ca8..fa50e9ede0e 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -426,7 +426,7 @@ config ENCLOSURE_SERVICES config SGI_XP tristate "Support communication between SGI SSIs" - depends on IA64_GENERIC || IA64_SGI_SN2 + depends on IA64_GENERIC || IA64_SGI_SN2 || IA64_SGI_UV || (X86_64 && SMP) select IA64_UNCACHED_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 select GENERIC_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 ---help--- diff --git a/drivers/misc/sgi-xp/Makefile b/drivers/misc/sgi-xp/Makefile index b3eeff31ebf..35ce2857807 100644 --- a/drivers/misc/sgi-xp/Makefile +++ b/drivers/misc/sgi-xp/Makefile @@ -3,11 +3,17 @@ # obj-$(CONFIG_SGI_XP) += xp.o -xp-y := xp_main.o xp_uv.o -xp-$(CONFIG_IA64) += xp_sn2.o xp_nofault.o +xp-y := xp_main.o +xp-$(CONFIG_IA64_SGI_SN2) += xp_sn2.o xp_nofault.o +xp-$(CONFIG_IA64_GENERIC) += xp_sn2.o xp_nofault.o xp_uv.o +xp-$(CONFIG_IA64_SGI_UV) += xp_uv.o +xp-$(CONFIG_X86_64) += xp_uv.o obj-$(CONFIG_SGI_XP) += xpc.o -xpc-y := xpc_main.o xpc_uv.o xpc_channel.o xpc_partition.o -xpc-$(CONFIG_IA64) += xpc_sn2.o +xpc-y := xpc_main.o xpc_channel.o xpc_partition.o +xpc-$(CONFIG_IA64_SGI_SN2) += xpc_sn2.o +xpc-$(CONFIG_IA64_GENERIC) += xpc_sn2.o xpc_uv.o +xpc-$(CONFIG_IA64_SGI_UV) += xpc_uv.o +xpc-$(CONFIG_X86_64) += xpc_uv.o obj-$(CONFIG_SGI_XP) += xpnet.o diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index 3054fae8b02..01bf1a2cd8e 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -13,18 +13,17 @@ #ifndef _DRIVERS_MISC_SGIXP_XP_H #define _DRIVERS_MISC_SGIXP_XP_H -#include -#include #include -#include + #ifdef CONFIG_IA64 -#include +#include +#include /* defines is_shub1() and is_shub2() */ +#define is_shub() ia64_platform_is("sn2") +#define is_uv() ia64_platform_is("uv") #endif - -#ifdef USE_DBUG_ON -#define DBUG_ON(condition) BUG_ON(condition) -#else -#define DBUG_ON(condition) +#ifdef CONFIG_X86_64 +#include +#define is_uv() is_uv_system() #endif #ifndef is_shub1 @@ -36,13 +35,19 @@ #endif #ifndef is_shub -#define is_shub() (is_shub1() || is_shub2()) +#define is_shub() 0 #endif #ifndef is_uv #define is_uv() 0 #endif +#ifdef USE_DBUG_ON +#define DBUG_ON(condition) BUG_ON(condition) +#else +#define DBUG_ON(condition) +#endif + /* * Define the maximum number of partitions the system can possibly support. * It is based on the maximum number of hardware partitionable regions. The @@ -200,7 +205,9 @@ enum xp_retval { xpPayloadTooBig, /* 55: payload too large for message slot */ xpUnsupported, /* 56: unsupported functionality or resource */ - xpUnknownReason /* 57: unknown reason - must be last in enum */ + xpNeedMoreInfo, /* 57: more info is needed by SAL */ + + xpUnknownReason /* 58: unknown reason - must be last in enum */ }; /* @@ -339,8 +346,11 @@ xpc_partid_to_nasids(short partid, void *nasids) } extern short xp_max_npartitions; +extern short xp_partition_id; +extern u8 xp_region_size; extern enum xp_retval (*xp_remote_memcpy) (void *, const void *, size_t); +extern int (*xp_cpu_to_nasid) (int); extern u64 xp_nofault_PIOR_target; extern int xp_nofault_PIOR(void *); diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c index 9c0ce2f15ff..c34b23fe498 100644 --- a/drivers/misc/sgi-xp/xp_main.c +++ b/drivers/misc/sgi-xp/xp_main.c @@ -14,7 +14,6 @@ * */ -#include #include #include #include "xp.h" @@ -36,9 +35,18 @@ struct device *xp = &xp_dbg_subname; short xp_max_npartitions; EXPORT_SYMBOL_GPL(xp_max_npartitions); +short xp_partition_id; +EXPORT_SYMBOL_GPL(xp_partition_id); + +u8 xp_region_size; +EXPORT_SYMBOL_GPL(xp_region_size); + enum xp_retval (*xp_remote_memcpy) (void *dst, const void *src, size_t len); EXPORT_SYMBOL_GPL(xp_remote_memcpy); +int (*xp_cpu_to_nasid) (int cpuid); +EXPORT_SYMBOL_GPL(xp_cpu_to_nasid); + /* * xpc_registrations[] keeps track of xpc_connect()'s done by the kernel-level * users of XPC. diff --git a/drivers/misc/sgi-xp/xp_sn2.c b/drivers/misc/sgi-xp/xp_sn2.c index baabc1cb3fe..c6a1ede7d6e 100644 --- a/drivers/misc/sgi-xp/xp_sn2.c +++ b/drivers/misc/sgi-xp/xp_sn2.c @@ -12,6 +12,7 @@ * Architecture specific implementation of common functions. */ +#include #include #include #include @@ -116,14 +117,23 @@ xp_remote_memcpy_sn2(void *vdst, const void *psrc, size_t len) return xpBteCopyError; } +static int +xp_cpu_to_nasid_sn2(int cpuid) +{ + return cpuid_to_nasid(cpuid); +} + enum xp_retval xp_init_sn2(void) { BUG_ON(!is_shub()); xp_max_npartitions = XP_MAX_NPARTITIONS_SN2; + xp_partition_id = sn_partition_id; + xp_region_size = sn_region_size; xp_remote_memcpy = xp_remote_memcpy_sn2; + xp_cpu_to_nasid = xp_cpu_to_nasid_sn2; return xp_register_nofault_code_sn2(); } diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index e194d3140f6..96408fcf5a1 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -13,17 +13,10 @@ #ifndef _DRIVERS_MISC_SGIXP_XPC_H #define _DRIVERS_MISC_SGIXP_XPC_H -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include +#include +#include #include "xp.h" /* @@ -179,7 +172,8 @@ struct xpc_vars_part_sn2 { #define XPC_RP_HEADER_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_rsvd_page)) #define XPC_RP_VARS_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_vars_sn2)) -#define XPC_RP_PART_NASIDS(_rp) ((u64 *)((u8 *)(_rp) + XPC_RP_HEADER_SIZE)) +#define XPC_RP_PART_NASIDS(_rp) ((unsigned long *)((u8 *)(_rp) + \ + XPC_RP_HEADER_SIZE)) #define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + \ xpc_nasid_mask_nlongs) #define XPC_RP_VARS(_rp) ((struct xpc_vars_sn2 *) \ @@ -202,13 +196,13 @@ struct xpc_vars_part_sn2 { /* * Define a Get/Put value pair (pointers) used with a message queue. */ -struct xpc_gp { +struct xpc_gp_sn2 { s64 get; /* Get value */ s64 put; /* Put value */ }; #define XPC_GP_SIZE \ - L1_CACHE_ALIGN(sizeof(struct xpc_gp) * XPC_MAX_NCHANNELS) + L1_CACHE_ALIGN(sizeof(struct xpc_gp_sn2) * XPC_MAX_NCHANNELS) /* * Define a structure that contains arguments associated with opening and @@ -340,10 +334,10 @@ struct xpc_channel_sn2 { /* various flavors of local and remote Get/Put values */ - struct xpc_gp *local_GP; /* local Get/Put values */ - struct xpc_gp remote_GP; /* remote Get/Put values */ - struct xpc_gp w_local_GP; /* working local Get/Put values */ - struct xpc_gp w_remote_GP; /* working remote Get/Put values */ + struct xpc_gp_sn2 *local_GP; /* local Get/Put values */ + struct xpc_gp_sn2 remote_GP; /* remote Get/Put values */ + struct xpc_gp_sn2 w_local_GP; /* working local Get/Put values */ + struct xpc_gp_sn2 w_remote_GP; /* working remote Get/Put values */ s64 next_msg_to_pull; /* Put value of next msg to pull */ struct mutex msg_to_pull_mutex; /* next msg to pull serialization */ @@ -506,9 +500,9 @@ struct xpc_partition_sn2 { u8 remote_vars_version; /* version# of partition's vars */ void *local_GPs_base; /* base address of kmalloc'd space */ - struct xpc_gp *local_GPs; /* local Get/Put values */ + struct xpc_gp_sn2 *local_GPs; /* local Get/Put values */ void *remote_GPs_base; /* base address of kmalloc'd space */ - struct xpc_gp *remote_GPs; /* copy of remote partition's local */ + struct xpc_gp_sn2 *remote_GPs; /* copy of remote partition's local */ /* Get/Put values */ u64 remote_GPs_pa; /* phys address of remote partition's local */ /* Get/Put values */ @@ -629,6 +623,8 @@ extern void xpc_activate_partition(struct xpc_partition *); extern void xpc_activate_kthreads(struct xpc_channel *, int); extern void xpc_create_kthreads(struct xpc_channel *, int, int); extern void xpc_disconnect_wait(int); +extern enum xp_retval (*xpc_get_partition_rsvd_page_pa) (u64, u64 *, u64 *, + size_t *); extern enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *); extern void (*xpc_heartbeat_init) (void); extern void (*xpc_heartbeat_exit) (void); diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index f1afc0a7c33..0615efbe007 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -14,14 +14,7 @@ * */ -#include -#include -#include -#include -#include -#include -#include -#include +#include #include "xpc.h" /* @@ -373,8 +366,9 @@ again: dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY (local_msgqueue_pa=" "0x%lx, local_nentries=%d, remote_nentries=%d) " "received from partid=%d, channel=%d\n", - args->local_msgqueue_pa, args->local_nentries, - args->remote_nentries, ch->partid, ch->number); + (unsigned long)args->local_msgqueue_pa, + args->local_nentries, args->remote_nentries, + ch->partid, ch->number); if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED)) { spin_unlock_irqrestore(&ch->lock, irq_flags); @@ -940,7 +934,7 @@ xpc_deliver_msg(struct xpc_channel *ch) if (ch->func != NULL) { dev_dbg(xpc_chan, "ch->func() called, msg=0x%p, " "msg_number=%ld, partid=%d, channel=%d\n", - (void *)msg, msg->number, ch->partid, + msg, (signed long)msg->number, ch->partid, ch->number); /* deliver the message to its intended recipient */ @@ -949,7 +943,7 @@ xpc_deliver_msg(struct xpc_channel *ch) dev_dbg(xpc_chan, "ch->func() returned, msg=0x%p, " "msg_number=%ld, partid=%d, channel=%d\n", - (void *)msg, msg->number, ch->partid, + msg, (signed long)msg->number, ch->partid, ch->number); } diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index e7ff9e1670f..f7478cc3572 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -43,19 +43,13 @@ * */ -#include #include -#include -#include -#include +#include +#include #include #include -#include #include #include -#include -#include -#include #include "xpc.h" /* define two XPC debug device structures to be used with dev_dbg() et al */ @@ -175,6 +169,8 @@ static struct notifier_block xpc_die_notifier = { .notifier_call = xpc_system_die, }; +enum xp_retval (*xpc_get_partition_rsvd_page_pa) (u64 buf, u64 *cookie, + u64 *paddr, size_t *len); enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *rp); void (*xpc_heartbeat_init) (void); void (*xpc_heartbeat_exit) (void); @@ -920,7 +916,8 @@ xpc_die_deactivate(void) struct xpc_partition *part; short partid; int any_engaged; - long time, printmsg_time, disengage_timeout; + long keep_waiting; + long wait_to_print; /* keep xpc_hb_checker thread from doing anything (just in case) */ xpc_exiting = 1; @@ -937,16 +934,17 @@ xpc_die_deactivate(void) } } - time = rtc_time(); - printmsg_time = time + - (XPC_DEACTIVATE_PRINTMSG_INTERVAL * sn_rtc_cycles_per_second); - disengage_timeout = time + - (xpc_disengage_timelimit * sn_rtc_cycles_per_second); - /* * Though we requested that all other partitions deactivate from us, - * we only wait until they've all disengaged. + * we only wait until they've all disengaged or we've reached the + * defined timelimit. + * + * Given that one iteration through the following while-loop takes + * approximately 200 microseconds, calculate the #of loops to take + * before bailing and the #of loops before printing a waiting message. */ + keep_waiting = xpc_disengage_timelimit * 1000 * 5; + wait_to_print = XPC_DEACTIVATE_PRINTMSG_INTERVAL * 1000 * 5; while (1) { any_engaged = xpc_any_partition_engaged(); @@ -955,8 +953,7 @@ xpc_die_deactivate(void) break; } - time = rtc_time(); - if (time >= disengage_timeout) { + if (!keep_waiting--) { for (partid = 0; partid < xp_max_npartitions; partid++) { if (xpc_partition_engaged(partid)) { @@ -968,15 +965,15 @@ xpc_die_deactivate(void) break; } - if (time >= printmsg_time) { + if (!wait_to_print--) { dev_info(xpc_part, "waiting for remote partitions to " "deactivate, timeout in %ld seconds\n", - (disengage_timeout - time) / - sn_rtc_cycles_per_second); - printmsg_time = time + - (XPC_DEACTIVATE_PRINTMSG_INTERVAL * - sn_rtc_cycles_per_second); + keep_waiting / (1000 * 5)); + wait_to_print = XPC_DEACTIVATE_PRINTMSG_INTERVAL * + 1000 * 5; } + + udelay(200); } } @@ -991,6 +988,7 @@ xpc_die_deactivate(void) static int xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) { +#ifdef CONFIG_IA64 /* !!! temporary kludge */ switch (event) { case DIE_MACHINE_RESTART: case DIE_MACHINE_HALT: @@ -1019,6 +1017,9 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) xpc_online_heartbeat(); break; } +#else + xpc_die_deactivate(); +#endif return NOTIFY_DONE; } diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 70d4a00c972..f84d6641020 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -15,15 +15,8 @@ * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include #include "xpc.h" /* XPC is exiting flag */ @@ -71,24 +64,23 @@ static u64 xpc_get_rsvd_page_pa(int nasid) { enum xp_retval ret; - s64 status; u64 cookie = 0; u64 rp_pa = nasid; /* seed with nasid */ - u64 len = 0; + size_t len = 0; u64 buf = buf; u64 buf_len = 0; void *buf_base = NULL; while (1) { - status = sn_partition_reserved_page_pa(buf, &cookie, &rp_pa, - &len); + ret = xpc_get_partition_rsvd_page_pa(buf, &cookie, &rp_pa, + &len); - dev_dbg(xpc_part, "SAL returned with status=%li, cookie=" - "0x%016lx, address=0x%016lx, len=0x%016lx\n", - status, cookie, rp_pa, len); + dev_dbg(xpc_part, "SAL returned with ret=%d, cookie=0x%016lx, " + "address=0x%016lx, len=0x%016lx\n", ret, + (unsigned long)cookie, (unsigned long)rp_pa, len); - if (status != SALRET_MORE_PASSES) + if (ret != xpNeedMoreInfo) break; /* !!! L1_CACHE_ALIGN() is only a sn2-bte_copy requirement */ @@ -100,8 +92,9 @@ xpc_get_rsvd_page_pa(int nasid) &buf_base); if (buf_base == NULL) { dev_err(xpc_part, "unable to kmalloc " - "len=0x%016lx\n", buf_len); - status = SALRET_ERROR; + "len=0x%016lx\n", + (unsigned long)buf_len); + ret = xpNoMemory; break; } } @@ -109,17 +102,17 @@ xpc_get_rsvd_page_pa(int nasid) ret = xp_remote_memcpy((void *)buf, (void *)rp_pa, buf_len); if (ret != xpSuccess) { dev_dbg(xpc_part, "xp_remote_memcpy failed %d\n", ret); - status = SALRET_ERROR; break; } } kfree(buf_base); - if (status != SALRET_OK) + if (ret != xpSuccess) rp_pa = 0; - dev_dbg(xpc_part, "reserved page at phys address 0x%016lx\n", rp_pa); + dev_dbg(xpc_part, "reserved page at phys address 0x%016lx\n", + (unsigned long)rp_pa); return rp_pa; } @@ -138,7 +131,7 @@ xpc_setup_rsvd_page(void) /* get the local reserved page's address */ preempt_disable(); - rp_pa = xpc_get_rsvd_page_pa(cpuid_to_nasid(smp_processor_id())); + rp_pa = xpc_get_rsvd_page_pa(xp_cpu_to_nasid(smp_processor_id())); preempt_enable(); if (rp_pa == 0) { dev_err(xpc_part, "SAL failed to locate the reserved page\n"); @@ -150,7 +143,7 @@ xpc_setup_rsvd_page(void) /* SAL_versions < 3 had a SAL_partid defined as a u8 */ rp->SAL_partid &= 0xff; } - BUG_ON(rp->SAL_partid != sn_partition_id); + BUG_ON(rp->SAL_partid != xp_partition_id); if (rp->SAL_partid < 0 || rp->SAL_partid >= xp_max_npartitions) { dev_err(xpc_part, "the reserved page's partid of %d is outside " @@ -237,11 +230,11 @@ xpc_get_remote_rp(int nasid, unsigned long *discovered_nasids, /* check that both remote and local partids are valid for each side */ if (remote_rp->SAL_partid < 0 || remote_rp->SAL_partid >= xp_max_npartitions || - remote_rp->max_npartitions <= sn_partition_id) { + remote_rp->max_npartitions <= xp_partition_id) { return xpInvalidPartid; } - if (remote_rp->SAL_partid == sn_partition_id) + if (remote_rp->SAL_partid == xp_partition_id) return xpLocalPartid; return xpSuccess; @@ -426,7 +419,7 @@ xpc_discovery(void) * protection is in regards to memory, IOI and IPI. */ max_regions = 64; - region_size = sn_region_size; + region_size = xp_region_size; switch (region_size) { case 128: diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index 4b5f69edf0d..fde870aebcb 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -13,9 +13,9 @@ * */ -#include #include #include +#include #include #include "xpc.h" @@ -176,7 +176,7 @@ xpc_send_IRQ_sn2(struct amo *amo, u64 flag, int nasid, int phys_cpuid, local_irq_restore(irq_flags); - return ((ret == 0) ? xpSuccess : xpPioReadError); + return (ret == 0) ? xpSuccess : xpPioReadError; } static struct amo * @@ -284,7 +284,7 @@ xpc_handle_notify_IRQ_sn2(int irq, void *dev_id) short partid = (short)(u64)dev_id; struct xpc_partition *part = &xpc_partitions[partid]; - DBUG_ON(partid < 0 || partid >= xp_max_npartitions); + DBUG_ON(partid < 0 || partid >= XP_MAX_NPARTITIONS_SN2); if (xpc_part_ref(part)) { xpc_check_for_sent_chctl_flags_sn2(part); @@ -576,6 +576,25 @@ xpc_allow_amo_ops_shub_wars_1_1_sn2(void) } } +static enum xp_retval +xpc_get_partition_rsvd_page_pa_sn2(u64 buf, u64 *cookie, u64 *paddr, + size_t *len) +{ + s64 status; + enum xp_retval ret; + + status = sn_partition_reserved_page_pa(buf, cookie, paddr, len); + if (status == SALRET_OK) + ret = xpSuccess; + else if (status == SALRET_MORE_PASSES) + ret = xpNeedMoreInfo; + else + ret = xpSalError; + + return ret; +} + + static enum xp_retval xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) { @@ -636,7 +655,7 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) /* clear xpc_vars_part_sn2 */ memset((u64 *)xpc_vars_part_sn2, 0, sizeof(struct xpc_vars_part_sn2) * - xp_max_npartitions); + XP_MAX_NPARTITIONS_SN2); /* initialize the activate IRQ related amo variables */ for (i = 0; i < xpc_nasid_mask_nlongs; i++) @@ -699,7 +718,7 @@ xpc_check_remote_hb_sn2(void) remote_vars = (struct xpc_vars_sn2 *)xpc_remote_copy_buffer_sn2; - for (partid = 0; partid < xp_max_npartitions; partid++) { + for (partid = 0; partid < XP_MAX_NPARTITIONS_SN2; partid++) { if (xpc_exiting) break; @@ -2386,6 +2405,7 @@ xpc_init_sn2(void) int ret; size_t buf_size; + xpc_get_partition_rsvd_page_pa = xpc_get_partition_rsvd_page_pa_sn2; xpc_rsvd_page_init = xpc_rsvd_page_init_sn2; xpc_increment_heartbeat = xpc_increment_heartbeat_sn2; xpc_offline_heartbeat = xpc_offline_heartbeat_sn2; diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index 2aec1dfbb3d..232867aa692 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c @@ -14,11 +14,8 @@ */ #include - -/* !!! #include */ -/* !!! uv_gpa() is defined in */ -#define uv_gpa(_a) ((unsigned long)_a) - +#include +#include "../sgi-gru/grukservices.h" #include "xpc.h" static DECLARE_BITMAP(xpc_heartbeating_to_mask_uv, XP_MAX_NPARTITIONS_UV); diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 07c89c4e2c2..49385f44170 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -21,17 +21,8 @@ */ #include -#include -#include -#include #include #include -#include -#include -#include -#include -#include -#include #include "xp.h" /* @@ -175,8 +166,9 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) return; } - dev_dbg(xpnet, "received 0x%lx, %d, %d, %d\n", msg->buf_pa, msg->size, - msg->leadin_ignore, msg->tailout_ignore); + dev_dbg(xpnet, "received 0x%lx, %d, %d, %d\n", + (unsigned long)msg->buf_pa, msg->size, msg->leadin_ignore, + msg->tailout_ignore); /* reserve an extra cache line */ skb = dev_alloc_skb(msg->size + L1_CACHE_BYTES); @@ -320,8 +312,10 @@ xpnet_dev_open(struct net_device *dev) dev_dbg(xpnet, "calling xpc_connect(%d, 0x%p, NULL, %ld, %ld, %ld, " "%ld)\n", XPC_NET_CHANNEL, xpnet_connection_activity, - XPNET_MSG_SIZE, XPNET_MSG_NENTRIES, XPNET_MAX_KTHREADS, - XPNET_MAX_IDLE_KTHREADS); + (unsigned long)XPNET_MSG_SIZE, + (unsigned long)XPNET_MSG_NENTRIES, + (unsigned long)XPNET_MAX_KTHREADS, + (unsigned long)XPNET_MAX_IDLE_KTHREADS); ret = xpc_connect(XPC_NET_CHANNEL, xpnet_connection_activity, NULL, XPNET_MSG_SIZE, XPNET_MSG_NENTRIES, @@ -439,8 +433,8 @@ xpnet_send(struct sk_buff *skb, struct xpnet_pending_msg *queued_msg, dev_dbg(xpnet, "sending XPC message to %d:%d\n" KERN_DEBUG "msg->buf_pa=0x%lx, msg->size=%u, " "msg->leadin_ignore=%u, msg->tailout_ignore=%u\n", - dest_partid, XPC_NET_CHANNEL, msg->buf_pa, msg->size, - msg->leadin_ignore, msg->tailout_ignore); + dest_partid, XPC_NET_CHANNEL, (unsigned long)msg->buf_pa, + msg->size, msg->leadin_ignore, msg->tailout_ignore); atomic_inc(&queued_msg->use_count); @@ -602,8 +596,8 @@ xpnet_init(void) */ xpnet_device->dev_addr[0] = 0x02; /* locally administered, no OUI */ - xpnet_device->dev_addr[XPNET_PARTID_OCTET + 1] = sn_partition_id; - xpnet_device->dev_addr[XPNET_PARTID_OCTET + 0] = (sn_partition_id >> 8); + xpnet_device->dev_addr[XPNET_PARTID_OCTET + 1] = xp_partition_id; + xpnet_device->dev_addr[XPNET_PARTID_OCTET + 0] = (xp_partition_id >> 8); /* * ether_setup() sets this to a multicast device. We are -- cgit v1.2.3 From a812dcc3a298eef650c381e094e2cf41a4ecc9ad Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:16 -0700 Subject: sgi-xp: add usage of GRU driver by xpc_remote_memcpy() Add UV support to xpc_remote_memcpy(), which involves interfacing to the GRU driver. Signed-off-by: Dean Nelson Cc: Jack Steiner Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xp.h | 8 +++-- drivers/misc/sgi-xp/xp_main.c | 6 +++- drivers/misc/sgi-xp/xp_sn2.c | 50 +++++++++++++-------------- drivers/misc/sgi-xp/xp_uv.c | 27 +++++++++++++-- drivers/misc/sgi-xp/xpc.h | 44 ++++++++++++------------ drivers/misc/sgi-xp/xpc_channel.c | 5 ++- drivers/misc/sgi-xp/xpc_main.c | 8 +++-- drivers/misc/sgi-xp/xpc_partition.c | 37 ++++++++++---------- drivers/misc/sgi-xp/xpc_sn2.c | 68 ++++++++++++++++++++----------------- drivers/misc/sgi-xp/xpc_uv.c | 2 +- drivers/misc/sgi-xp/xpnet.c | 26 ++++++-------- 11 files changed, 154 insertions(+), 127 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index 01bf1a2cd8e..45d0a08c2dd 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -207,7 +207,9 @@ enum xp_retval { xpUnsupported, /* 56: unsupported functionality or resource */ xpNeedMoreInfo, /* 57: more info is needed by SAL */ - xpUnknownReason /* 58: unknown reason - must be last in enum */ + xpGruCopyError, /* 58: gru_copy_gru() returned error */ + + xpUnknownReason /* 59: unknown reason - must be last in enum */ }; /* @@ -349,7 +351,9 @@ extern short xp_max_npartitions; extern short xp_partition_id; extern u8 xp_region_size; -extern enum xp_retval (*xp_remote_memcpy) (void *, const void *, size_t); +extern unsigned long (*xp_pa) (void *); +extern enum xp_retval (*xp_remote_memcpy) (unsigned long, const unsigned long, + size_t); extern int (*xp_cpu_to_nasid) (int); extern u64 xp_nofault_PIOR_target; diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c index c34b23fe498..f86ad3af26b 100644 --- a/drivers/misc/sgi-xp/xp_main.c +++ b/drivers/misc/sgi-xp/xp_main.c @@ -41,7 +41,11 @@ EXPORT_SYMBOL_GPL(xp_partition_id); u8 xp_region_size; EXPORT_SYMBOL_GPL(xp_region_size); -enum xp_retval (*xp_remote_memcpy) (void *dst, const void *src, size_t len); +unsigned long (*xp_pa) (void *addr); +EXPORT_SYMBOL_GPL(xp_pa); + +enum xp_retval (*xp_remote_memcpy) (unsigned long dst_gpa, + const unsigned long src_gpa, size_t len); EXPORT_SYMBOL_GPL(xp_remote_memcpy); int (*xp_cpu_to_nasid) (int cpuid); diff --git a/drivers/misc/sgi-xp/xp_sn2.c b/drivers/misc/sgi-xp/xp_sn2.c index c6a1ede7d6e..1440134caf3 100644 --- a/drivers/misc/sgi-xp/xp_sn2.c +++ b/drivers/misc/sgi-xp/xp_sn2.c @@ -63,7 +63,7 @@ xp_register_nofault_code_sn2(void) return xpSuccess; } -void +static void xp_unregister_nofault_code_sn2(void) { u64 func_addr = *(u64 *)xp_nofault_PIOR; @@ -74,45 +74,42 @@ xp_unregister_nofault_code_sn2(void) err_func_addr, 1, 0); } +/* + * Convert a virtual memory address to a physical memory address. + */ +static unsigned long +xp_pa_sn2(void *addr) +{ + return __pa(addr); +} + /* * Wrapper for bte_copy(). * - * vdst - virtual address of the destination of the transfer. - * psrc - physical address of the source of the transfer. + * dst_pa - physical address of the destination of the transfer. + * src_pa - physical address of the source of the transfer. * len - number of bytes to transfer from source to destination. * * Note: xp_remote_memcpy_sn2() should never be called while holding a spinlock. */ static enum xp_retval -xp_remote_memcpy_sn2(void *vdst, const void *psrc, size_t len) +xp_remote_memcpy_sn2(unsigned long dst_pa, const unsigned long src_pa, + size_t len) { bte_result_t ret; - u64 pdst = ia64_tpa(vdst); - /* ??? What are the rules governing the src and dst addresses passed in? - * ??? Currently we're assuming that dst is a virtual address and src - * ??? is a physical address, is this appropriate? Can we allow them to - * ??? be whatever and we make the change here without damaging the - * ??? addresses? - */ - /* - * Ensure that the physically mapped memory is contiguous. - * - * We do this by ensuring that the memory is from region 7 only. - * If the need should arise to use memory from one of the other - * regions, then modify the BUG_ON() statement to ensure that the - * memory from that region is always physically contiguous. - */ - BUG_ON(REGION_NUMBER(vdst) != RGN_KERNEL); - - ret = bte_copy((u64)psrc, pdst, len, (BTE_NOTIFY | BTE_WACQUIRE), NULL); + ret = bte_copy(src_pa, dst_pa, len, (BTE_NOTIFY | BTE_WACQUIRE), NULL); if (ret == BTE_SUCCESS) return xpSuccess; - if (is_shub2()) - dev_err(xp, "bte_copy() on shub2 failed, error=0x%x\n", ret); - else - dev_err(xp, "bte_copy() failed, error=%d\n", ret); + if (is_shub2()) { + dev_err(xp, "bte_copy() on shub2 failed, error=0x%x dst_pa=" + "0x%016lx src_pa=0x%016lx len=%ld\\n", ret, dst_pa, + src_pa, len); + } else { + dev_err(xp, "bte_copy() failed, error=%d dst_pa=0x%016lx " + "src_pa=0x%016lx len=%ld\\n", ret, dst_pa, src_pa, len); + } return xpBteCopyError; } @@ -132,6 +129,7 @@ xp_init_sn2(void) xp_partition_id = sn_partition_id; xp_region_size = sn_region_size; + xp_pa = xp_pa_sn2; xp_remote_memcpy = xp_remote_memcpy_sn2; xp_cpu_to_nasid = xp_cpu_to_nasid_sn2; diff --git a/drivers/misc/sgi-xp/xp_uv.c b/drivers/misc/sgi-xp/xp_uv.c index 382b1b6bcc0..44f2c2b58c2 100644 --- a/drivers/misc/sgi-xp/xp_uv.c +++ b/drivers/misc/sgi-xp/xp_uv.c @@ -13,13 +13,33 @@ * */ +#include +#include +#include "../sgi-gru/grukservices.h" #include "xp.h" +/* + * Convert a virtual memory address to a physical memory address. + */ +static unsigned long +xp_pa_uv(void *addr) +{ + return uv_gpa(addr); +} + static enum xp_retval -xp_remote_memcpy_uv(void *vdst, const void *psrc, size_t len) +xp_remote_memcpy_uv(unsigned long dst_gpa, const unsigned long src_gpa, + size_t len) { - /* !!! this function needs fleshing out */ - return xpUnsupported; + int ret; + + ret = gru_copy_gpa(dst_gpa, src_gpa, len); + if (ret == 0) + return xpSuccess; + + dev_err(xp, "gru_copy_gpa() failed, dst_gpa=0x%016lx src_gpa=0x%016lx " + "len=%ld\n", dst_gpa, src_gpa, len); + return xpGruCopyError; } enum xp_retval @@ -29,6 +49,7 @@ xp_init_uv(void) xp_max_npartitions = XP_MAX_NPARTITIONS_UV; + xp_pa = xp_pa_uv; xp_remote_memcpy = xp_remote_memcpy_uv; return xpSuccess; diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 96408fcf5a1..49e26993345 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -91,8 +91,8 @@ struct xpc_rsvd_page { u8 version; u8 pad1[3]; /* align to next u64 in 1st 64-byte cacheline */ union { - u64 vars_pa; /* physical address of struct xpc_vars */ - u64 activate_mq_gpa; /* global phys address of activate_mq */ + unsigned long vars_pa; /* phys address of struct xpc_vars */ + unsigned long activate_mq_gpa; /* gru phy addr of activate_mq */ } sn; unsigned long ts_jiffies; /* timestamp when rsvd pg was setup by XPC */ u64 pad2[10]; /* align to last u64 in 2nd 64-byte cacheline */ @@ -122,8 +122,8 @@ struct xpc_vars_sn2 { u64 heartbeat_offline; /* if 0, heartbeat should be changing */ int activate_IRQ_nasid; int activate_IRQ_phys_cpuid; - u64 vars_part_pa; - u64 amos_page_pa; /* paddr of page of amos from MSPEC driver */ + unsigned long vars_part_pa; + unsigned long amos_page_pa;/* paddr of page of amos from MSPEC driver */ struct amo *amos_page; /* vaddr of page of amos from MSPEC driver */ }; @@ -142,10 +142,10 @@ struct xpc_vars_sn2 { struct xpc_vars_part_sn2 { u64 magic; - u64 openclose_args_pa; /* physical address of open and close args */ - u64 GPs_pa; /* physical address of Get/Put values */ + unsigned long openclose_args_pa; /* phys addr of open and close args */ + unsigned long GPs_pa; /* physical address of Get/Put values */ - u64 chctl_amo_pa; /* physical address of chctl flags' amo */ + unsigned long chctl_amo_pa; /* physical address of chctl flags' amo */ int notify_IRQ_nasid; /* nasid of where to send notify IRQs */ int notify_IRQ_phys_cpuid; /* CPUID of where to send notify IRQs */ @@ -213,7 +213,7 @@ struct xpc_openclose_args { u16 msg_size; /* sizeof each message entry */ u16 remote_nentries; /* #of message entries in remote msg queue */ u16 local_nentries; /* #of message entries in local msg queue */ - u64 local_msgqueue_pa; /* physical address of local message queue */ + unsigned long local_msgqueue_pa; /* phys addr of local message queue */ }; #define XPC_OPENCLOSE_ARGS_SIZE \ @@ -366,8 +366,8 @@ struct xpc_channel { void *remote_msgqueue_base; /* base address of kmalloc'd space */ struct xpc_msg *remote_msgqueue; /* cached copy of remote partition's */ /* local message queue */ - u64 remote_msgqueue_pa; /* phys addr of remote partition's */ - /* local message queue */ + unsigned long remote_msgqueue_pa; /* phys addr of remote partition's */ + /* local message queue */ atomic_t references; /* #of external references to queues */ @@ -491,12 +491,12 @@ xpc_any_msg_chctl_flags_set(union xpc_channel_ctl_flags *chctl) */ struct xpc_partition_sn2 { - u64 remote_amos_page_pa; /* phys addr of partition's amos page */ + unsigned long remote_amos_page_pa; /* paddr of partition's amos page */ int activate_IRQ_nasid; /* active partition's act/deact nasid */ int activate_IRQ_phys_cpuid; /* active part's act/deact phys cpuid */ - u64 remote_vars_pa; /* phys addr of partition's vars */ - u64 remote_vars_part_pa; /* phys addr of partition's vars part */ + unsigned long remote_vars_pa; /* phys addr of partition's vars */ + unsigned long remote_vars_part_pa; /* paddr of partition's vars part */ u8 remote_vars_version; /* version# of partition's vars */ void *local_GPs_base; /* base address of kmalloc'd space */ @@ -504,10 +504,10 @@ struct xpc_partition_sn2 { void *remote_GPs_base; /* base address of kmalloc'd space */ struct xpc_gp_sn2 *remote_GPs; /* copy of remote partition's local */ /* Get/Put values */ - u64 remote_GPs_pa; /* phys address of remote partition's local */ - /* Get/Put values */ + unsigned long remote_GPs_pa; /* phys addr of remote partition's local */ + /* Get/Put values */ - u64 remote_openclose_args_pa; /* phys addr of remote's args */ + unsigned long remote_openclose_args_pa; /* phys addr of remote's args */ int notify_IRQ_nasid; /* nasid of where to send notify IRQs */ int notify_IRQ_phys_cpuid; /* CPUID of where to send notify IRQs */ @@ -529,7 +529,7 @@ struct xpc_partition { u8 remote_rp_version; /* version# of partition's rsvd pg */ unsigned long remote_rp_ts_jiffies; /* timestamp when rsvd pg setup */ - u64 remote_rp_pa; /* phys addr of partition's rsvd pg */ + unsigned long remote_rp_pa; /* phys addr of partition's rsvd pg */ u64 last_heartbeat; /* HB at last read */ u32 activate_IRQ_rcvd; /* IRQs since activation */ spinlock_t act_lock; /* protect updating of act_state */ @@ -623,7 +623,8 @@ extern void xpc_activate_partition(struct xpc_partition *); extern void xpc_activate_kthreads(struct xpc_channel *, int); extern void xpc_create_kthreads(struct xpc_channel *, int, int); extern void xpc_disconnect_wait(int); -extern enum xp_retval (*xpc_get_partition_rsvd_page_pa) (u64, u64 *, u64 *, +extern enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *, u64 *, + unsigned long *, size_t *); extern enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *); extern void (*xpc_heartbeat_init) (void); @@ -640,8 +641,8 @@ extern void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *); extern void (*xpc_process_msg_chctl_flags) (struct xpc_partition *, int); extern int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *); extern struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *); -extern void (*xpc_request_partition_activation) (struct xpc_rsvd_page *, u64, - int); +extern void (*xpc_request_partition_activation) (struct xpc_rsvd_page *, + unsigned long, int); extern void (*xpc_request_partition_reactivation) (struct xpc_partition *); extern void (*xpc_request_partition_deactivation) (struct xpc_partition *); extern void (*xpc_cancel_partition_deactivation_request) ( @@ -690,7 +691,8 @@ extern enum xp_retval xpc_mark_partition_active(struct xpc_partition *); extern void xpc_mark_partition_inactive(struct xpc_partition *); extern void xpc_discovery(void); extern enum xp_retval xpc_get_remote_rp(int, unsigned long *, - struct xpc_rsvd_page *, u64 *); + struct xpc_rsvd_page *, + unsigned long *); extern void xpc_deactivate_partition(const int, struct xpc_partition *, enum xp_retval); extern enum xp_retval xpc_initiate_partid_to_nasids(short, void *); diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index 0615efbe007..d7a15f1a78a 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -366,9 +366,8 @@ again: dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY (local_msgqueue_pa=" "0x%lx, local_nentries=%d, remote_nentries=%d) " "received from partid=%d, channel=%d\n", - (unsigned long)args->local_msgqueue_pa, - args->local_nentries, args->remote_nentries, - ch->partid, ch->number); + args->local_msgqueue_pa, args->local_nentries, + args->remote_nentries, ch->partid, ch->number); if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_DISCONNECTED)) { spin_unlock_irqrestore(&ch->lock, irq_flags); diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index f7478cc3572..dc686110aef 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -169,8 +169,9 @@ static struct notifier_block xpc_die_notifier = { .notifier_call = xpc_system_die, }; -enum xp_retval (*xpc_get_partition_rsvd_page_pa) (u64 buf, u64 *cookie, - u64 *paddr, size_t *len); +enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *buf, u64 *cookie, + unsigned long *rp_pa, + size_t *len); enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *rp); void (*xpc_heartbeat_init) (void); void (*xpc_heartbeat_exit) (void); @@ -189,7 +190,8 @@ int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *ch); struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *ch); void (*xpc_request_partition_activation) (struct xpc_rsvd_page *remote_rp, - u64 remote_rp_pa, int nasid); + unsigned long remote_rp_pa, + int nasid); void (*xpc_request_partition_reactivation) (struct xpc_partition *part); void (*xpc_request_partition_deactivation) (struct xpc_partition *part); void (*xpc_cancel_partition_deactivation_request) (struct xpc_partition *part); diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index f84d6641020..f150dbfcfcc 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -60,15 +60,15 @@ xpc_kmalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) * Given a nasid, get the physical address of the partition's reserved page * for that nasid. This function returns 0 on any error. */ -static u64 +static unsigned long xpc_get_rsvd_page_pa(int nasid) { enum xp_retval ret; u64 cookie = 0; - u64 rp_pa = nasid; /* seed with nasid */ + unsigned long rp_pa = nasid; /* seed with nasid */ size_t len = 0; - u64 buf = buf; - u64 buf_len = 0; + size_t buf_len = 0; + void *buf = buf; void *buf_base = NULL; while (1) { @@ -78,7 +78,7 @@ xpc_get_rsvd_page_pa(int nasid) dev_dbg(xpc_part, "SAL returned with ret=%d, cookie=0x%016lx, " "address=0x%016lx, len=0x%016lx\n", ret, - (unsigned long)cookie, (unsigned long)rp_pa, len); + (unsigned long)cookie, rp_pa, len); if (ret != xpNeedMoreInfo) break; @@ -87,19 +87,17 @@ xpc_get_rsvd_page_pa(int nasid) if (L1_CACHE_ALIGN(len) > buf_len) { kfree(buf_base); buf_len = L1_CACHE_ALIGN(len); - buf = (u64)xpc_kmalloc_cacheline_aligned(buf_len, - GFP_KERNEL, - &buf_base); + buf = xpc_kmalloc_cacheline_aligned(buf_len, GFP_KERNEL, + &buf_base); if (buf_base == NULL) { dev_err(xpc_part, "unable to kmalloc " - "len=0x%016lx\n", - (unsigned long)buf_len); + "len=0x%016lx\n", buf_len); ret = xpNoMemory; break; } } - ret = xp_remote_memcpy((void *)buf, (void *)rp_pa, buf_len); + ret = xp_remote_memcpy(xp_pa(buf), rp_pa, buf_len); if (ret != xpSuccess) { dev_dbg(xpc_part, "xp_remote_memcpy failed %d\n", ret); break; @@ -111,8 +109,7 @@ xpc_get_rsvd_page_pa(int nasid) if (ret != xpSuccess) rp_pa = 0; - dev_dbg(xpc_part, "reserved page at phys address 0x%016lx\n", - (unsigned long)rp_pa); + dev_dbg(xpc_part, "reserved page at phys address 0x%016lx\n", rp_pa); return rp_pa; } @@ -125,7 +122,7 @@ struct xpc_rsvd_page * xpc_setup_rsvd_page(void) { struct xpc_rsvd_page *rp; - u64 rp_pa; + unsigned long rp_pa; unsigned long new_ts_jiffies; /* get the local reserved page's address */ @@ -193,7 +190,7 @@ xpc_setup_rsvd_page(void) */ enum xp_retval xpc_get_remote_rp(int nasid, unsigned long *discovered_nasids, - struct xpc_rsvd_page *remote_rp, u64 *remote_rp_pa) + struct xpc_rsvd_page *remote_rp, unsigned long *remote_rp_pa) { int l; enum xp_retval ret; @@ -205,7 +202,7 @@ xpc_get_remote_rp(int nasid, unsigned long *discovered_nasids, return xpNoRsvdPageAddr; /* pull over the reserved page header and part_nasids mask */ - ret = xp_remote_memcpy(remote_rp, (void *)*remote_rp_pa, + ret = xp_remote_memcpy(xp_pa(remote_rp), *remote_rp_pa, XPC_RP_HEADER_SIZE + xpc_nasid_mask_nbytes); if (ret != xpSuccess) return ret; @@ -389,7 +386,7 @@ xpc_discovery(void) { void *remote_rp_base; struct xpc_rsvd_page *remote_rp; - u64 remote_rp_pa; + unsigned long remote_rp_pa; int region; int region_size; int max_regions; @@ -500,7 +497,7 @@ enum xp_retval xpc_initiate_partid_to_nasids(short partid, void *nasid_mask) { struct xpc_partition *part; - u64 part_nasid_pa; + unsigned long part_nasid_pa; part = &xpc_partitions[partid]; if (part->remote_rp_pa == 0) @@ -508,8 +505,8 @@ xpc_initiate_partid_to_nasids(short partid, void *nasid_mask) memset(nasid_mask, 0, xpc_nasid_mask_nbytes); - part_nasid_pa = (u64)XPC_RP_PART_NASIDS(part->remote_rp_pa); + part_nasid_pa = (unsigned long)XPC_RP_PART_NASIDS(part->remote_rp_pa); - return xp_remote_memcpy(nasid_mask, (void *)part_nasid_pa, + return xp_remote_memcpy(xp_pa(nasid_mask), part_nasid_pa, xpc_nasid_mask_nbytes); } diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index fde870aebcb..1571a7cdf9d 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -207,8 +207,8 @@ xpc_handle_activate_IRQ_sn2(int irq, void *dev_id) * Flag the appropriate amo variable and send an IRQ to the specified node. */ static void -xpc_send_activate_IRQ_sn2(u64 amos_page_pa, int from_nasid, int to_nasid, - int to_phys_cpuid) +xpc_send_activate_IRQ_sn2(unsigned long amos_page_pa, int from_nasid, + int to_nasid, int to_phys_cpuid) { struct amo *amos = (struct amo *)__va(amos_page_pa + (XPC_ACTIVATE_IRQ_AMOS_SN2 * @@ -404,7 +404,7 @@ xpc_send_chctl_openreply_sn2(struct xpc_channel *ch, unsigned long *irq_flags) args->remote_nentries = ch->remote_nentries; args->local_nentries = ch->local_nentries; - args->local_msgqueue_pa = __pa(ch->local_msgqueue); + args->local_msgqueue_pa = xp_pa(ch->local_msgqueue); XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_OPENREPLY, irq_flags); } @@ -577,13 +577,13 @@ xpc_allow_amo_ops_shub_wars_1_1_sn2(void) } static enum xp_retval -xpc_get_partition_rsvd_page_pa_sn2(u64 buf, u64 *cookie, u64 *paddr, +xpc_get_partition_rsvd_page_pa_sn2(void *buf, u64 *cookie, unsigned long *rp_pa, size_t *len) { s64 status; enum xp_retval ret; - status = sn_partition_reserved_page_pa(buf, cookie, paddr, len); + status = sn_partition_reserved_page_pa((u64)buf, cookie, rp_pa, len); if (status == SALRET_OK) ret = xpSuccess; else if (status == SALRET_MORE_PASSES) @@ -604,7 +604,7 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) xpc_vars_sn2 = XPC_RP_VARS(rp); - rp->sn.vars_pa = __pa(xpc_vars_sn2); + rp->sn.vars_pa = xp_pa(xpc_vars_sn2); /* vars_part array follows immediately after vars */ xpc_vars_part_sn2 = (struct xpc_vars_part_sn2 *)((u8 *)XPC_RP_VARS(rp) + @@ -649,7 +649,7 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) xpc_vars_sn2->version = XPC_V_VERSION; xpc_vars_sn2->activate_IRQ_nasid = cpuid_to_nasid(0); xpc_vars_sn2->activate_IRQ_phys_cpuid = cpu_physical_id(0); - xpc_vars_sn2->vars_part_pa = __pa(xpc_vars_part_sn2); + xpc_vars_sn2->vars_part_pa = xp_pa(xpc_vars_part_sn2); xpc_vars_sn2->amos_page_pa = ia64_tpa((u64)amos_page); xpc_vars_sn2->amos_page = amos_page; /* save for next load of XPC */ @@ -734,8 +734,8 @@ xpc_check_remote_hb_sn2(void) } /* pull the remote_hb cache line */ - ret = xp_remote_memcpy(remote_vars, - (void *)part->sn.sn2.remote_vars_pa, + ret = xp_remote_memcpy(xp_pa(remote_vars), + part->sn.sn2.remote_vars_pa, XPC_RP_VARS_SIZE); if (ret != xpSuccess) { XPC_DEACTIVATE_PARTITION(part, ret); @@ -768,7 +768,8 @@ xpc_check_remote_hb_sn2(void) * assumed to be of size XPC_RP_VARS_SIZE. */ static enum xp_retval -xpc_get_remote_vars_sn2(u64 remote_vars_pa, struct xpc_vars_sn2 *remote_vars) +xpc_get_remote_vars_sn2(unsigned long remote_vars_pa, + struct xpc_vars_sn2 *remote_vars) { enum xp_retval ret; @@ -776,7 +777,7 @@ xpc_get_remote_vars_sn2(u64 remote_vars_pa, struct xpc_vars_sn2 *remote_vars) return xpVarsNotSet; /* pull over the cross partition variables */ - ret = xp_remote_memcpy(remote_vars, (void *)remote_vars_pa, + ret = xp_remote_memcpy(xp_pa(remote_vars), remote_vars_pa, XPC_RP_VARS_SIZE); if (ret != xpSuccess) return ret; @@ -791,7 +792,7 @@ xpc_get_remote_vars_sn2(u64 remote_vars_pa, struct xpc_vars_sn2 *remote_vars) static void xpc_request_partition_activation_sn2(struct xpc_rsvd_page *remote_rp, - u64 remote_rp_pa, int nasid) + unsigned long remote_rp_pa, int nasid) { xpc_send_local_activate_IRQ_sn2(nasid); } @@ -883,7 +884,8 @@ xpc_partition_deactivation_requested_sn2(short partid) static void xpc_update_partition_info_sn2(struct xpc_partition *part, u8 remote_rp_version, unsigned long *remote_rp_ts_jiffies, - u64 remote_rp_pa, u64 remote_vars_pa, + unsigned long remote_rp_pa, + unsigned long remote_vars_pa, struct xpc_vars_sn2 *remote_vars) { struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; @@ -948,8 +950,8 @@ xpc_identify_activate_IRQ_req_sn2(int nasid) { struct xpc_rsvd_page *remote_rp; struct xpc_vars_sn2 *remote_vars; - u64 remote_rp_pa; - u64 remote_vars_pa; + unsigned long remote_rp_pa; + unsigned long remote_vars_pa; int remote_rp_version; int reactivate = 0; unsigned long remote_rp_ts_jiffies = 0; @@ -1291,11 +1293,11 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) * The setting of the magic # indicates that these per partition * specific variables are ready to be used. */ - xpc_vars_part_sn2[partid].GPs_pa = __pa(part_sn2->local_GPs); + xpc_vars_part_sn2[partid].GPs_pa = xp_pa(part_sn2->local_GPs); xpc_vars_part_sn2[partid].openclose_args_pa = - __pa(part->local_openclose_args); + xp_pa(part->local_openclose_args); xpc_vars_part_sn2[partid].chctl_amo_pa = - __pa(part_sn2->local_chctl_amo_va); + xp_pa(part_sn2->local_chctl_amo_va); cpuid = raw_smp_processor_id(); /* any CPU in this partition will do */ xpc_vars_part_sn2[partid].notify_IRQ_nasid = cpuid_to_nasid(cpuid); xpc_vars_part_sn2[partid].notify_IRQ_phys_cpuid = @@ -1382,25 +1384,25 @@ xpc_teardown_infrastructure_sn2(struct xpc_partition *part) * Create a wrapper that hides the underlying mechanism for pulling a cacheline * (or multiple cachelines) from a remote partition. * - * src must be a cacheline aligned physical address on the remote partition. + * src_pa must be a cacheline aligned physical address on the remote partition. * dst must be a cacheline aligned virtual address on this partition. * cnt must be cacheline sized */ /* ??? Replace this function by call to xp_remote_memcpy() or bte_copy()? */ static enum xp_retval xpc_pull_remote_cachelines_sn2(struct xpc_partition *part, void *dst, - const void *src, size_t cnt) + const unsigned long src_pa, size_t cnt) { enum xp_retval ret; - DBUG_ON((u64)src != L1_CACHE_ALIGN((u64)src)); - DBUG_ON((u64)dst != L1_CACHE_ALIGN((u64)dst)); + DBUG_ON(src_pa != L1_CACHE_ALIGN(src_pa)); + DBUG_ON((unsigned long)dst != L1_CACHE_ALIGN((unsigned long)dst)); DBUG_ON(cnt != L1_CACHE_ALIGN(cnt)); if (part->act_state == XPC_P_DEACTIVATING) return part->reason; - ret = xp_remote_memcpy(dst, src, cnt); + ret = xp_remote_memcpy(xp_pa(dst), src_pa, cnt); if (ret != xpSuccess) { dev_dbg(xpc_chan, "xp_remote_memcpy() from partition %d failed," " ret=%d\n", XPC_PARTID(part), ret); @@ -1420,7 +1422,8 @@ xpc_pull_remote_vars_part_sn2(struct xpc_partition *part) struct xpc_vars_part_sn2 *pulled_entry_cacheline = (struct xpc_vars_part_sn2 *)L1_CACHE_ALIGN((u64)buffer); struct xpc_vars_part_sn2 *pulled_entry; - u64 remote_entry_cacheline_pa, remote_entry_pa; + unsigned long remote_entry_cacheline_pa; + unsigned long remote_entry_pa; short partid = XPC_PARTID(part); enum xp_retval ret; @@ -1440,7 +1443,7 @@ xpc_pull_remote_vars_part_sn2(struct xpc_partition *part) (L1_CACHE_BYTES - 1))); ret = xpc_pull_remote_cachelines_sn2(part, pulled_entry_cacheline, - (void *)remote_entry_cacheline_pa, + remote_entry_cacheline_pa, L1_CACHE_BYTES); if (ret != xpSuccess) { dev_dbg(xpc_chan, "failed to pull XPC vars_part from " @@ -1587,7 +1590,7 @@ xpc_get_chctl_all_flags_sn2(struct xpc_partition *part) if (xpc_any_openclose_chctl_flags_set(&chctl)) { ret = xpc_pull_remote_cachelines_sn2(part, part-> remote_openclose_args, - (void *)part_sn2-> + part_sn2-> remote_openclose_args_pa, XPC_OPENCLOSE_ARGS_SIZE); if (ret != xpSuccess) { @@ -1604,7 +1607,7 @@ xpc_get_chctl_all_flags_sn2(struct xpc_partition *part) if (xpc_any_msg_chctl_flags_set(&chctl)) { ret = xpc_pull_remote_cachelines_sn2(part, part_sn2->remote_GPs, - (void *)part_sn2->remote_GPs_pa, + part_sn2->remote_GPs_pa, XPC_GP_SIZE); if (ret != xpSuccess) { XPC_DEACTIVATE_PARTITION(part, ret); @@ -1971,8 +1974,10 @@ xpc_pull_remote_msg_sn2(struct xpc_channel *ch, s64 get) { struct xpc_partition *part = &xpc_partitions[ch->partid]; struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; - struct xpc_msg *remote_msg, *msg; - u32 msg_index, nmsgs; + unsigned long remote_msg_pa; + struct xpc_msg *msg; + u32 msg_index; + u32 nmsgs; u64 msg_offset; enum xp_retval ret; @@ -1996,10 +2001,9 @@ xpc_pull_remote_msg_sn2(struct xpc_channel *ch, s64 get) msg_offset = msg_index * ch->msg_size; msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + msg_offset); - remote_msg = (struct xpc_msg *)(ch->remote_msgqueue_pa + - msg_offset); + remote_msg_pa = ch->remote_msgqueue_pa + msg_offset; - ret = xpc_pull_remote_cachelines_sn2(part, msg, remote_msg, + ret = xpc_pull_remote_cachelines_sn2(part, msg, remote_msg_pa, nmsgs * ch->msg_size); if (ret != xpSuccess) { diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index 232867aa692..c2d4ddd6e95 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c @@ -61,7 +61,7 @@ xpc_heartbeat_exit_uv(void) static void xpc_request_partition_activation_uv(struct xpc_rsvd_page *remote_rp, - u64 remote_rp_pa, int nasid) + unsigned long remote_rp_pa, int nasid) { short partid = remote_rp->SAL_partid; struct xpc_partition *part = &xpc_partitions[partid]; diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 49385f44170..4f5d6223011 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -44,7 +44,7 @@ struct xpnet_message { u16 version; /* Version for this message */ u16 embedded_bytes; /* #of bytes embedded in XPC message */ u32 magic; /* Special number indicating this is xpnet */ - u64 buf_pa; /* phys address of buffer to retrieve */ + unsigned long buf_pa; /* phys address of buffer to retrieve */ u32 size; /* #of bytes in buffer */ u8 leadin_ignore; /* #of bytes to ignore at the beginning */ u8 tailout_ignore; /* #of bytes to ignore at the end */ @@ -152,6 +152,7 @@ static void xpnet_receive(short partid, int channel, struct xpnet_message *msg) { struct sk_buff *skb; + void *dst; enum xp_retval ret; struct xpnet_dev_private *priv = (struct xpnet_dev_private *)xpnet_device->priv; @@ -166,9 +167,8 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) return; } - dev_dbg(xpnet, "received 0x%lx, %d, %d, %d\n", - (unsigned long)msg->buf_pa, msg->size, msg->leadin_ignore, - msg->tailout_ignore); + dev_dbg(xpnet, "received 0x%lx, %d, %d, %d\n", msg->buf_pa, msg->size, + msg->leadin_ignore, msg->tailout_ignore); /* reserve an extra cache line */ skb = dev_alloc_skb(msg->size + L1_CACHE_BYTES); @@ -210,15 +210,12 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) skb_copy_to_linear_data(skb, &msg->data, (size_t)msg->embedded_bytes); } else { + dst = (void *)((u64)skb->data & ~(L1_CACHE_BYTES - 1)); dev_dbg(xpnet, "transferring buffer to the skb->data area;\n\t" - "xp_remote_memcpy(0x%p, 0x%p, %hu)\n", (void *) - ((u64)skb->data & ~(L1_CACHE_BYTES - 1)), + "xp_remote_memcpy(0x%p, 0x%p, %hu)\n", dst, (void *)msg->buf_pa, msg->size); - ret = xp_remote_memcpy((void *)((u64)skb->data & - ~(L1_CACHE_BYTES - 1)), - (void *)msg->buf_pa, msg->size); - + ret = xp_remote_memcpy(xp_pa(dst), msg->buf_pa, msg->size); if (ret != xpSuccess) { /* * !!! Need better way of cleaning skb. Currently skb @@ -226,8 +223,7 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) * !!! dev_kfree_skb. */ dev_err(xpnet, "xp_remote_memcpy(0x%p, 0x%p, 0x%hx) " - "returned error=0x%x\n", (void *) - ((u64)skb->data & ~(L1_CACHE_BYTES - 1)), + "returned error=0x%x\n", dst, (void *)msg->buf_pa, msg->size, ret); xpc_received(partid, channel, (void *)msg); @@ -428,13 +424,13 @@ xpnet_send(struct sk_buff *skb, struct xpnet_pending_msg *queued_msg, msg->size = end_addr - start_addr; msg->leadin_ignore = (u64)skb->data - start_addr; msg->tailout_ignore = end_addr - (u64)skb_tail_pointer(skb); - msg->buf_pa = __pa(start_addr); + msg->buf_pa = xp_pa((void *)start_addr); dev_dbg(xpnet, "sending XPC message to %d:%d\n" KERN_DEBUG "msg->buf_pa=0x%lx, msg->size=%u, " "msg->leadin_ignore=%u, msg->tailout_ignore=%u\n", - dest_partid, XPC_NET_CHANNEL, (unsigned long)msg->buf_pa, - msg->size, msg->leadin_ignore, msg->tailout_ignore); + dest_partid, XPC_NET_CHANNEL, msg->buf_pa, msg->size, + msg->leadin_ignore, msg->tailout_ignore); atomic_inc(&queued_msg->use_count); -- cgit v1.2.3 From 61deb86e98f51151b225f7563ee1cf2b50857d10 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:17 -0700 Subject: sgi-xp: move xpc_check_remote_hb() to support both SN2 and UV Move xpc_check_remote_hb() so it can support both SN2 and UV. Signed-off-by: Dean Nelson Cc: Jack Steiner Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xpc.h | 2 +- drivers/misc/sgi-xp/xpc_main.c | 34 +++++++++++++++++++- drivers/misc/sgi-xp/xpc_sn2.c | 70 ++++++++++++++---------------------------- 3 files changed, 57 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 49e26993345..f258f89b8d3 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -632,7 +632,7 @@ extern void (*xpc_heartbeat_exit) (void); extern void (*xpc_increment_heartbeat) (void); extern void (*xpc_offline_heartbeat) (void); extern void (*xpc_online_heartbeat) (void); -extern void (*xpc_check_remote_hb) (void); +extern enum xp_retval (*xpc_get_remote_heartbeat) (struct xpc_partition *); extern enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *); extern u64 (*xpc_get_chctl_all_flags) (struct xpc_partition *); extern enum xp_retval (*xpc_allocate_msgqueues) (struct xpc_channel *); diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index dc686110aef..f4d866113f2 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -178,7 +178,7 @@ void (*xpc_heartbeat_exit) (void); void (*xpc_increment_heartbeat) (void); void (*xpc_offline_heartbeat) (void); void (*xpc_online_heartbeat) (void); -void (*xpc_check_remote_hb) (void); +enum xp_retval (*xpc_get_remote_heartbeat) (struct xpc_partition *part); enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *part); void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *ch); @@ -269,6 +269,38 @@ xpc_stop_hb_beater(void) xpc_heartbeat_exit(); } +/* + * At periodic intervals, scan through all active partitions and ensure + * their heartbeat is still active. If not, the partition is deactivated. + */ +static void +xpc_check_remote_hb(void) +{ + struct xpc_partition *part; + short partid; + enum xp_retval ret; + + for (partid = 0; partid < xp_max_npartitions; partid++) { + + if (xpc_exiting) + break; + + if (partid == xp_partition_id) + continue; + + part = &xpc_partitions[partid]; + + if (part->act_state == XPC_P_INACTIVE || + part->act_state == XPC_P_DEACTIVATING) { + continue; + } + + ret = xpc_get_remote_heartbeat(part); + if (ret != xpSuccess) + XPC_DEACTIVATE_PARTITION(part, ret); + } +} + /* * This thread is responsible for nearly all of the partition * activation/deactivation. diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index 1571a7cdf9d..d34cdd533a9 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -704,61 +704,37 @@ xpc_heartbeat_exit_sn2(void) xpc_offline_heartbeat_sn2(); } -/* - * At periodic intervals, scan through all active partitions and ensure - * their heartbeat is still active. If not, the partition is deactivated. - */ -static void -xpc_check_remote_hb_sn2(void) +static enum xp_retval +xpc_get_remote_heartbeat_sn2(struct xpc_partition *part) { struct xpc_vars_sn2 *remote_vars; - struct xpc_partition *part; - short partid; enum xp_retval ret; remote_vars = (struct xpc_vars_sn2 *)xpc_remote_copy_buffer_sn2; - for (partid = 0; partid < XP_MAX_NPARTITIONS_SN2; partid++) { - - if (xpc_exiting) - break; - - if (partid == sn_partition_id) - continue; - - part = &xpc_partitions[partid]; - - if (part->act_state == XPC_P_INACTIVE || - part->act_state == XPC_P_DEACTIVATING) { - continue; - } - - /* pull the remote_hb cache line */ - ret = xp_remote_memcpy(xp_pa(remote_vars), - part->sn.sn2.remote_vars_pa, - XPC_RP_VARS_SIZE); - if (ret != xpSuccess) { - XPC_DEACTIVATE_PARTITION(part, ret); - continue; - } - - dev_dbg(xpc_part, "partid = %d, heartbeat = %ld, last_heartbeat" - " = %ld, heartbeat_offline = %ld, HB_mask[0] = 0x%lx\n", - partid, remote_vars->heartbeat, part->last_heartbeat, - remote_vars->heartbeat_offline, - remote_vars->heartbeating_to_mask[0]); - - if (((remote_vars->heartbeat == part->last_heartbeat) && - (remote_vars->heartbeat_offline == 0)) || - !xpc_hb_allowed(sn_partition_id, - &remote_vars->heartbeating_to_mask)) { - - XPC_DEACTIVATE_PARTITION(part, xpNoHeartbeat); - continue; - } + /* pull the remote vars structure that contains the heartbeat */ + ret = xp_remote_memcpy(xp_pa(remote_vars), + part->sn.sn2.remote_vars_pa, + XPC_RP_VARS_SIZE); + if (ret != xpSuccess) + return ret; + dev_dbg(xpc_part, "partid=%d, heartbeat=%ld, last_heartbeat=%ld, " + "heartbeat_offline=%ld, HB_mask[0]=0x%lx\n", XPC_PARTID(part), + remote_vars->heartbeat, part->last_heartbeat, + remote_vars->heartbeat_offline, + remote_vars->heartbeating_to_mask[0]); + + if ((remote_vars->heartbeat == part->last_heartbeat && + remote_vars->heartbeat_offline == 0) || + !xpc_hb_allowed(sn_partition_id, + &remote_vars->heartbeating_to_mask)) { + ret = xpNoHeartbeat; + } else { part->last_heartbeat = remote_vars->heartbeat; } + + return ret; } /* @@ -2416,7 +2392,7 @@ xpc_init_sn2(void) xpc_online_heartbeat = xpc_online_heartbeat_sn2; xpc_heartbeat_init = xpc_heartbeat_init_sn2; xpc_heartbeat_exit = xpc_heartbeat_exit_sn2; - xpc_check_remote_hb = xpc_check_remote_hb_sn2; + xpc_get_remote_heartbeat = xpc_get_remote_heartbeat_sn2; xpc_request_partition_activation = xpc_request_partition_activation_sn2; xpc_request_partition_reactivation = -- cgit v1.2.3 From 83469b5525b4a35be40b17cb41d64118d84d9f80 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:18 -0700 Subject: sgi-xp: cleanup naming of partition defines Cleanup naming of partition defines. Signed-off-by: Dean Nelson Cc: Jack Steiner Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xpc.h | 22 +++++++++++----------- drivers/misc/sgi-xp/xpc_channel.c | 10 +++++----- drivers/misc/sgi-xp/xpc_main.c | 32 ++++++++++++++++---------------- drivers/misc/sgi-xp/xpc_partition.c | 18 +++++++++--------- drivers/misc/sgi-xp/xpc_sn2.c | 20 ++++++++++---------- 5 files changed, 51 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index f258f89b8d3..1e48f776505 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -576,21 +576,21 @@ struct xpc_partition { /* struct xpc_partition act_state values (for XPC HB) */ -#define XPC_P_INACTIVE 0x00 /* partition is not active */ -#define XPC_P_ACTIVATION_REQ 0x01 /* created thread to activate */ -#define XPC_P_ACTIVATING 0x02 /* activation thread started */ -#define XPC_P_ACTIVE 0x03 /* xpc_partition_up() was called */ -#define XPC_P_DEACTIVATING 0x04 /* partition deactivation initiated */ +#define XPC_P_AS_INACTIVE 0x00 /* partition is not active */ +#define XPC_P_AS_ACTIVATION_REQ 0x01 /* created thread to activate */ +#define XPC_P_AS_ACTIVATING 0x02 /* activation thread started */ +#define XPC_P_AS_ACTIVE 0x03 /* xpc_partition_up() was called */ +#define XPC_P_AS_DEACTIVATING 0x04 /* partition deactivation initiated */ #define XPC_DEACTIVATE_PARTITION(_p, _reason) \ xpc_deactivate_partition(__LINE__, (_p), (_reason)) /* struct xpc_partition setup_state values */ -#define XPC_P_UNSET 0x00 /* infrastructure was never setup */ -#define XPC_P_SETUP 0x01 /* infrastructure is setup */ -#define XPC_P_WTEARDOWN 0x02 /* waiting to teardown infrastructure */ -#define XPC_P_TORNDOWN 0x03 /* infrastructure is torndown */ +#define XPC_P_SS_UNSET 0x00 /* infrastructure was never setup */ +#define XPC_P_SS_SETUP 0x01 /* infrastructure is setup */ +#define XPC_P_SS_WTEARDOWN 0x02 /* waiting to teardown infrastructure */ +#define XPC_P_SS_TORNDOWN 0x03 /* infrastructure is torndown */ /* * struct xpc_partition_sn2's dropped notify IRQ timer is set to wait the @@ -787,7 +787,7 @@ xpc_part_deref(struct xpc_partition *part) s32 refs = atomic_dec_return(&part->references); DBUG_ON(refs < 0); - if (refs == 0 && part->setup_state == XPC_P_WTEARDOWN) + if (refs == 0 && part->setup_state == XPC_P_SS_WTEARDOWN) wake_up(&part->teardown_wq); } @@ -797,7 +797,7 @@ xpc_part_ref(struct xpc_partition *part) int setup; atomic_inc(&part->references); - setup = (part->setup_state == XPC_P_SETUP); + setup = (part->setup_state == XPC_P_SS_SETUP); if (!setup) xpc_part_deref(part); diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index d7a15f1a78a..17ab75d69e8 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -99,7 +99,7 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) DBUG_ON((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) && !(ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE)); - if (part->act_state == XPC_P_DEACTIVATING) { + if (part->act_state == XPC_P_AS_DEACTIVATING) { /* can't proceed until the other side disengages from us */ if (xpc_partition_engaged(ch->partid)) return; @@ -155,7 +155,7 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) /* we won't lose the CPU since we're holding ch->lock */ complete(&ch->wdisconnect_wait); } else if (ch->delayed_chctl_flags) { - if (part->act_state != XPC_P_DEACTIVATING) { + if (part->act_state != XPC_P_AS_DEACTIVATING) { /* time to take action on any delayed chctl flags */ spin_lock(&part->chctl_lock); part->chctl.flags[ch->number] |= @@ -276,7 +276,7 @@ again: "%d, channel=%d\n", ch->partid, ch->number); if (ch->flags & XPC_C_DISCONNECTED) { - DBUG_ON(part->act_state != XPC_P_DEACTIVATING); + DBUG_ON(part->act_state != XPC_P_AS_DEACTIVATING); spin_unlock_irqrestore(&ch->lock, irq_flags); return; } @@ -312,7 +312,7 @@ again: "channel=%d\n", args->msg_size, args->local_nentries, ch->partid, ch->number); - if (part->act_state == XPC_P_DEACTIVATING || + if (part->act_state == XPC_P_AS_DEACTIVATING || (ch->flags & XPC_C_ROPENREQUEST)) { spin_unlock_irqrestore(&ch->lock, irq_flags); return; @@ -546,7 +546,7 @@ xpc_process_sent_chctl_flags(struct xpc_partition *part) continue; } - if (part->act_state == XPC_P_DEACTIVATING) + if (part->act_state == XPC_P_AS_DEACTIVATING) continue; if (!(ch_flags & XPC_C_CONNECTED)) { diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index f4d866113f2..b303c130bba 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -290,8 +290,8 @@ xpc_check_remote_hb(void) part = &xpc_partitions[partid]; - if (part->act_state == XPC_P_INACTIVE || - part->act_state == XPC_P_DEACTIVATING) { + if (part->act_state == XPC_P_AS_INACTIVE || + part->act_state == XPC_P_AS_DEACTIVATING) { continue; } @@ -406,7 +406,7 @@ xpc_initiate_discovery(void *ignore) static void xpc_channel_mgr(struct xpc_partition *part) { - while (part->act_state != XPC_P_DEACTIVATING || + while (part->act_state != XPC_P_AS_DEACTIVATING || atomic_read(&part->nchannels_active) > 0 || !xpc_partition_disengaged(part)) { @@ -429,7 +429,7 @@ xpc_channel_mgr(struct xpc_partition *part) (void)wait_event_interruptible(part->channel_mgr_wq, (atomic_read(&part->channel_mgr_requests) > 0 || part->chctl.all_flags != 0 || - (part->act_state == XPC_P_DEACTIVATING && + (part->act_state == XPC_P_AS_DEACTIVATING && atomic_read(&part->nchannels_active) == 0 && xpc_partition_disengaged(part)))); atomic_set(&part->channel_mgr_requests, 1); @@ -458,16 +458,16 @@ xpc_activating(void *__partid) spin_lock_irqsave(&part->act_lock, irq_flags); - if (part->act_state == XPC_P_DEACTIVATING) { - part->act_state = XPC_P_INACTIVE; + if (part->act_state == XPC_P_AS_DEACTIVATING) { + part->act_state = XPC_P_AS_INACTIVE; spin_unlock_irqrestore(&part->act_lock, irq_flags); part->remote_rp_pa = 0; return 0; } /* indicate the thread is activating */ - DBUG_ON(part->act_state != XPC_P_ACTIVATION_REQ); - part->act_state = XPC_P_ACTIVATING; + DBUG_ON(part->act_state != XPC_P_AS_ACTIVATION_REQ); + part->act_state = XPC_P_AS_ACTIVATING; XPC_SET_REASON(part, 0, 0); spin_unlock_irqrestore(&part->act_lock, irq_flags); @@ -509,9 +509,9 @@ xpc_activate_partition(struct xpc_partition *part) spin_lock_irqsave(&part->act_lock, irq_flags); - DBUG_ON(part->act_state != XPC_P_INACTIVE); + DBUG_ON(part->act_state != XPC_P_AS_INACTIVE); - part->act_state = XPC_P_ACTIVATION_REQ; + part->act_state = XPC_P_AS_ACTIVATION_REQ; XPC_SET_REASON(part, xpCloneKThread, __LINE__); spin_unlock_irqrestore(&part->act_lock, irq_flags); @@ -520,7 +520,7 @@ xpc_activate_partition(struct xpc_partition *part) partid); if (IS_ERR(kthread)) { spin_lock_irqsave(&part->act_lock, irq_flags); - part->act_state = XPC_P_INACTIVE; + part->act_state = XPC_P_AS_INACTIVE; XPC_SET_REASON(part, xpCloneKThreadFailed, __LINE__); spin_unlock_irqrestore(&part->act_lock, irq_flags); } @@ -786,7 +786,7 @@ xpc_disconnect_wait(int ch_number) wakeup_channel_mgr = 0; if (ch->delayed_chctl_flags) { - if (part->act_state != XPC_P_DEACTIVATING) { + if (part->act_state != XPC_P_AS_DEACTIVATING) { spin_lock(&part->chctl_lock); part->chctl.flags[ch->number] |= ch->delayed_chctl_flags; @@ -846,7 +846,7 @@ xpc_do_exit(enum xp_retval reason) part = &xpc_partitions[partid]; if (xpc_partition_disengaged(part) && - part->act_state == XPC_P_INACTIVE) { + part->act_state == XPC_P_AS_INACTIVE) { continue; } @@ -962,7 +962,7 @@ xpc_die_deactivate(void) part = &xpc_partitions[partid]; if (xpc_partition_engaged(partid) || - part->act_state != XPC_P_INACTIVE) { + part->act_state != XPC_P_AS_INACTIVE) { xpc_request_partition_deactivation(part); xpc_indicate_partition_disengaged(part); } @@ -1113,7 +1113,7 @@ xpc_init(void) part->activate_IRQ_rcvd = 0; spin_lock_init(&part->act_lock); - part->act_state = XPC_P_INACTIVE; + part->act_state = XPC_P_AS_INACTIVE; XPC_SET_REASON(part, 0, 0); init_timer(&part->disengage_timer); @@ -1121,7 +1121,7 @@ xpc_init(void) xpc_timeout_partition_disengage; part->disengage_timer.data = (unsigned long)part; - part->setup_state = XPC_P_UNSET; + part->setup_state = XPC_P_SS_UNSET; init_waitqueue_head(&part->teardown_wq); atomic_set(&part->references, 0); } diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index f150dbfcfcc..b5fb2164113 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -273,9 +273,9 @@ xpc_partition_disengaged(struct xpc_partition *part) if (!in_interrupt()) del_singleshot_timer_sync(&part->disengage_timer); - DBUG_ON(part->act_state != XPC_P_DEACTIVATING && - part->act_state != XPC_P_INACTIVE); - if (part->act_state != XPC_P_INACTIVE) + DBUG_ON(part->act_state != XPC_P_AS_DEACTIVATING && + part->act_state != XPC_P_AS_INACTIVE); + if (part->act_state != XPC_P_AS_INACTIVE) xpc_wakeup_channel_mgr(part); xpc_cancel_partition_deactivation_request(part); @@ -295,8 +295,8 @@ xpc_mark_partition_active(struct xpc_partition *part) dev_dbg(xpc_part, "setting partition %d to ACTIVE\n", XPC_PARTID(part)); spin_lock_irqsave(&part->act_lock, irq_flags); - if (part->act_state == XPC_P_ACTIVATING) { - part->act_state = XPC_P_ACTIVE; + if (part->act_state == XPC_P_AS_ACTIVATING) { + part->act_state = XPC_P_AS_ACTIVE; ret = xpSuccess; } else { DBUG_ON(part->reason == xpSuccess); @@ -318,7 +318,7 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part, spin_lock_irqsave(&part->act_lock, irq_flags); - if (part->act_state == XPC_P_INACTIVE) { + if (part->act_state == XPC_P_AS_INACTIVE) { XPC_SET_REASON(part, reason, line); spin_unlock_irqrestore(&part->act_lock, irq_flags); if (reason == xpReactivating) { @@ -327,7 +327,7 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part, } return; } - if (part->act_state == XPC_P_DEACTIVATING) { + if (part->act_state == XPC_P_AS_DEACTIVATING) { if ((part->reason == xpUnloading && reason != xpUnloading) || reason == xpReactivating) { XPC_SET_REASON(part, reason, line); @@ -336,7 +336,7 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part, return; } - part->act_state = XPC_P_DEACTIVATING; + part->act_state = XPC_P_AS_DEACTIVATING; XPC_SET_REASON(part, reason, line); spin_unlock_irqrestore(&part->act_lock, irq_flags); @@ -367,7 +367,7 @@ xpc_mark_partition_inactive(struct xpc_partition *part) XPC_PARTID(part)); spin_lock_irqsave(&part->act_lock, irq_flags); - part->act_state = XPC_P_INACTIVE; + part->act_state = XPC_P_AS_INACTIVE; spin_unlock_irqrestore(&part->act_lock, irq_flags); part->remote_rp_pa = 0; } diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index d34cdd533a9..d1ccadc0857 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -327,7 +327,7 @@ xpc_send_notify_IRQ_sn2(struct xpc_channel *ch, u8 chctl_flag, union xpc_channel_ctl_flags chctl = { 0 }; enum xp_retval ret; - if (likely(part->act_state != XPC_P_DEACTIVATING)) { + if (likely(part->act_state != XPC_P_AS_DEACTIVATING)) { chctl.flags[ch->number] = chctl_flag; ret = xpc_send_IRQ_sn2(part_sn2->remote_chctl_amo_va, chctl.all_flags, @@ -975,7 +975,7 @@ xpc_identify_activate_IRQ_req_sn2(int nasid) remote_vars->heartbeat, remote_vars->heartbeating_to_mask[0]); if (xpc_partition_disengaged(part) && - part->act_state == XPC_P_INACTIVE) { + part->act_state == XPC_P_AS_INACTIVE) { xpc_update_partition_info_sn2(part, remote_rp_version, &remote_rp_ts_jiffies, @@ -1257,10 +1257,10 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) } /* - * With the setting of the partition setup_state to XPC_P_SETUP, we're - * declaring that this partition is ready to go. + * With the setting of the partition setup_state to XPC_P_SS_SETUP, + * we're declaring that this partition is ready to go. */ - part->setup_state = XPC_P_SETUP; + part->setup_state = XPC_P_SS_SETUP; /* * Setup the per partition specific variables required by the @@ -1323,8 +1323,8 @@ xpc_teardown_infrastructure_sn2(struct xpc_partition *part) DBUG_ON(atomic_read(&part->nchannels_engaged) != 0); DBUG_ON(atomic_read(&part->nchannels_active) != 0); - DBUG_ON(part->setup_state != XPC_P_SETUP); - part->setup_state = XPC_P_WTEARDOWN; + DBUG_ON(part->setup_state != XPC_P_SS_SETUP); + part->setup_state = XPC_P_SS_WTEARDOWN; xpc_vars_part_sn2[partid].magic = 0; @@ -1338,7 +1338,7 @@ xpc_teardown_infrastructure_sn2(struct xpc_partition *part) /* now we can begin tearing down the infrastructure */ - part->setup_state = XPC_P_TORNDOWN; + part->setup_state = XPC_P_SS_TORNDOWN; /* in case we've still got outstanding timers registered... */ del_timer_sync(&part_sn2->dropped_notify_IRQ_timer); @@ -1375,7 +1375,7 @@ xpc_pull_remote_cachelines_sn2(struct xpc_partition *part, void *dst, DBUG_ON((unsigned long)dst != L1_CACHE_ALIGN((unsigned long)dst)); DBUG_ON(cnt != L1_CACHE_ALIGN(cnt)); - if (part->act_state == XPC_P_DEACTIVATING) + if (part->act_state == XPC_P_AS_DEACTIVATING) return part->reason; ret = xp_remote_memcpy(xp_pa(dst), src_pa, cnt); @@ -1534,7 +1534,7 @@ xpc_make_first_contact_sn2(struct xpc_partition *part) /* wait a 1/4 of a second or so */ (void)msleep_interruptible(250); - if (part->act_state == XPC_P_DEACTIVATING) + if (part->act_state == XPC_P_AS_DEACTIVATING) return part->reason; } -- cgit v1.2.3 From 5b8669dfd110a62a74eea525a009342f73987ea0 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:18 -0700 Subject: sgi-xp: setup the activate GRU message queue Setup the activate GRU message queue that is used for partition activation and channel connection on UV systems. Signed-off-by: Dean Nelson Cc: Jack Steiner Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xp.h | 3 +- drivers/misc/sgi-xp/xp_uv.c | 10 + drivers/misc/sgi-xp/xpc.h | 158 ++++++-- drivers/misc/sgi-xp/xpc_channel.c | 22 +- drivers/misc/sgi-xp/xpc_main.c | 329 +++++++++++---- drivers/misc/sgi-xp/xpc_partition.c | 28 +- drivers/misc/sgi-xp/xpc_sn2.c | 387 +++++++----------- drivers/misc/sgi-xp/xpc_uv.c | 781 ++++++++++++++++++++++++++++++++++-- 8 files changed, 1328 insertions(+), 390 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index 45d0a08c2dd..9ac5758f4d0 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -208,8 +208,9 @@ enum xp_retval { xpNeedMoreInfo, /* 57: more info is needed by SAL */ xpGruCopyError, /* 58: gru_copy_gru() returned error */ + xpGruSendMqError, /* 59: gru send message queue related error */ - xpUnknownReason /* 59: unknown reason - must be last in enum */ + xpUnknownReason /* 60: unknown reason - must be last in enum */ }; /* diff --git a/drivers/misc/sgi-xp/xp_uv.c b/drivers/misc/sgi-xp/xp_uv.c index 44f2c2b58c2..d9f7ce2510b 100644 --- a/drivers/misc/sgi-xp/xp_uv.c +++ b/drivers/misc/sgi-xp/xp_uv.c @@ -42,15 +42,25 @@ xp_remote_memcpy_uv(unsigned long dst_gpa, const unsigned long src_gpa, return xpGruCopyError; } +static int +xp_cpu_to_nasid_uv(int cpuid) +{ + /* ??? Is this same as sn2 nasid in mach/part bitmaps set up by SAL? */ + return UV_PNODE_TO_NASID(uv_cpu_to_pnode(cpuid)); +} + enum xp_retval xp_init_uv(void) { BUG_ON(!is_uv()); xp_max_npartitions = XP_MAX_NPARTITIONS_UV; + xp_partition_id = 0; /* !!! not correct value */ + xp_region_size = 0; /* !!! not correct value */ xp_pa = xp_pa_uv; xp_remote_memcpy = xp_remote_memcpy_uv; + xp_cpu_to_nasid = xp_cpu_to_nasid_uv; return xpSuccess; } diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 1e48f776505..4c26181deff 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -164,8 +164,8 @@ struct xpc_vars_part_sn2 { * MAGIC2 indicates that this partition has pulled the remote partititions * per partition variables that pertain to this partition. */ -#define XPC_VP_MAGIC1 0x0053524156435058L /* 'XPCVARS\0'L (little endian) */ -#define XPC_VP_MAGIC2 0x0073726176435058L /* 'XPCvars\0'L (little endian) */ +#define XPC_VP_MAGIC1_SN2 0x0053524156435058L /* 'XPCVARS\0'L (little endian) */ +#define XPC_VP_MAGIC2_SN2 0x0073726176435058L /* 'XPCvars\0'L (little endian) */ /* the reserved page sizes and offsets */ @@ -180,6 +180,80 @@ struct xpc_vars_part_sn2 { (XPC_RP_MACH_NASIDS(_rp) + \ xpc_nasid_mask_nlongs)) +/* + * The activate_mq is used to send/receive messages that affect XPC's heartbeat, + * partition active state, and channel state. This is UV only. + */ +struct xpc_activate_mq_msghdr_uv { + short partid; /* sender's partid */ + u8 act_state; /* sender's act_state at time msg sent */ + u8 type; /* message's type */ + unsigned long rp_ts_jiffies; /* timestamp of sender's rp setup by XPC */ +}; + +/* activate_mq defined message types */ +#define XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV 0 +#define XPC_ACTIVATE_MQ_MSG_INC_HEARTBEAT_UV 1 +#define XPC_ACTIVATE_MQ_MSG_OFFLINE_HEARTBEAT_UV 2 +#define XPC_ACTIVATE_MQ_MSG_ONLINE_HEARTBEAT_UV 3 + +#define XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV 4 +#define XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV 5 + +#define XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV 6 +#define XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV 7 +#define XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV 8 +#define XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV 9 + +#define XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV 10 +#define XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV 11 + +struct xpc_activate_mq_msg_uv { + struct xpc_activate_mq_msghdr_uv header; +}; + +struct xpc_activate_mq_msg_heartbeat_req_uv { + struct xpc_activate_mq_msghdr_uv header; + u64 heartbeat; +}; + +struct xpc_activate_mq_msg_activate_req_uv { + struct xpc_activate_mq_msghdr_uv header; + unsigned long rp_gpa; + unsigned long activate_mq_gpa; +}; + +struct xpc_activate_mq_msg_deactivate_req_uv { + struct xpc_activate_mq_msghdr_uv header; + enum xp_retval reason; +}; + +struct xpc_activate_mq_msg_chctl_closerequest_uv { + struct xpc_activate_mq_msghdr_uv header; + short ch_number; + enum xp_retval reason; +}; + +struct xpc_activate_mq_msg_chctl_closereply_uv { + struct xpc_activate_mq_msghdr_uv header; + short ch_number; +}; + +struct xpc_activate_mq_msg_chctl_openrequest_uv { + struct xpc_activate_mq_msghdr_uv header; + short ch_number; + short msg_size; /* size of notify_mq's messages */ + short local_nentries; /* ??? Is this needed? What is? */ +}; + +struct xpc_activate_mq_msg_chctl_openreply_uv { + struct xpc_activate_mq_msghdr_uv header; + short ch_number; + short remote_nentries; /* ??? Is this needed? What is? */ + short local_nentries; /* ??? Is this needed? What is? */ + unsigned long local_notify_mq_gpa; +}; + /* * Functions registered by add_timer() or called by kernel_thread() only * allow for a single 64-bit argument. The following macros can be used to @@ -331,6 +405,18 @@ struct xpc_notify { */ struct xpc_channel_sn2 { + struct xpc_openclose_args *local_openclose_args; /* args passed on */ + /* opening or closing of channel */ + + void *local_msgqueue_base; /* base address of kmalloc'd space */ + struct xpc_msg *local_msgqueue; /* local message queue */ + void *remote_msgqueue_base; /* base address of kmalloc'd space */ + struct xpc_msg *remote_msgqueue; /* cached copy of remote partition's */ + /* local message queue */ + unsigned long remote_msgqueue_pa; /* phys addr of remote partition's */ + /* local message queue */ + + struct xpc_notify *notify_queue; /* notify queue for messages sent */ /* various flavors of local and remote Get/Put values */ @@ -344,13 +430,14 @@ struct xpc_channel_sn2 { }; struct xpc_channel_uv { - /* !!! code is coming */ + unsigned long remote_notify_mq_gpa; /* gru phys address of remote */ + /* partition's notify mq */ }; struct xpc_channel { short partid; /* ID of remote partition connected */ spinlock_t lock; /* lock for updating this structure */ - u32 flags; /* general flags */ + unsigned int flags; /* general flags */ enum xp_retval reason; /* reason why channel is disconnect'g */ int reason_line; /* line# disconnect initiated from */ @@ -361,14 +448,6 @@ struct xpc_channel { u16 local_nentries; /* #of msg entries in local msg queue */ u16 remote_nentries; /* #of msg entries in remote msg queue */ - void *local_msgqueue_base; /* base address of kmalloc'd space */ - struct xpc_msg *local_msgqueue; /* local message queue */ - void *remote_msgqueue_base; /* base address of kmalloc'd space */ - struct xpc_msg *remote_msgqueue; /* cached copy of remote partition's */ - /* local message queue */ - unsigned long remote_msgqueue_pa; /* phys addr of remote partition's */ - /* local message queue */ - atomic_t references; /* #of external references to queues */ atomic_t n_on_msg_allocate_wq; /* #on msg allocation wait queue */ @@ -377,19 +456,13 @@ struct xpc_channel { u8 delayed_chctl_flags; /* chctl flags received, but delayed */ /* action until channel disconnected */ - /* queue of msg senders who want to be notified when msg received */ - atomic_t n_to_notify; /* #of msg senders to notify */ - struct xpc_notify *notify_queue; /* notify queue for messages sent */ xpc_channel_func func; /* user's channel function */ void *key; /* pointer to user's key */ struct completion wdisconnect_wait; /* wait for channel disconnect */ - struct xpc_openclose_args *local_openclose_args; /* args passed on */ - /* opening or closing of channel */ - /* kthread management related fields */ atomic_t kthreads_assigned; /* #of kthreads assigned to channel */ @@ -507,6 +580,8 @@ struct xpc_partition_sn2 { unsigned long remote_GPs_pa; /* phys addr of remote partition's local */ /* Get/Put values */ + void *local_openclose_args_base; /* base address of kmalloc'd space */ + struct xpc_openclose_args *local_openclose_args; /* local's args */ unsigned long remote_openclose_args_pa; /* phys addr of remote's args */ int notify_IRQ_nasid; /* nasid of where to send notify IRQs */ @@ -520,9 +595,27 @@ struct xpc_partition_sn2 { }; struct xpc_partition_uv { - /* !!! code is coming */ + unsigned long remote_activate_mq_gpa; /* gru phys address of remote */ + /* partition's activate mq */ + spinlock_t flags_lock; /* protect updating of flags */ + unsigned int flags; /* general flags */ + u8 remote_act_state; /* remote partition's act_state */ + u8 act_state_req; /* act_state request from remote partition */ + enum xp_retval reason; /* reason for deactivate act_state request */ + u64 heartbeat; /* incremented by remote partition */ }; +/* struct xpc_partition_uv flags */ + +#define XPC_P_HEARTBEAT_OFFLINE_UV 0x00000001 +#define XPC_P_ENGAGED_UV 0x00000002 + +/* struct xpc_partition_uv act_state change requests */ + +#define XPC_P_ASR_ACTIVATE_UV 0x01 +#define XPC_P_ASR_REACTIVATE_UV 0x02 +#define XPC_P_ASR_DEACTIVATE_UV 0x03 + struct xpc_partition { /* XPC HB infrastructure */ @@ -556,8 +649,6 @@ struct xpc_partition { union xpc_channel_ctl_flags chctl; /* chctl flags yet to be processed */ spinlock_t chctl_lock; /* chctl flags lock */ - void *local_openclose_args_base; /* base address of kmalloc'd space */ - struct xpc_openclose_args *local_openclose_args; /* local's args */ void *remote_openclose_args_base; /* base address of kmalloc'd space */ struct xpc_openclose_args *remote_openclose_args; /* copy of remote's */ /* args */ @@ -616,17 +707,20 @@ extern struct device *xpc_part; extern struct device *xpc_chan; extern int xpc_disengage_timelimit; extern int xpc_disengage_timedout; -extern atomic_t xpc_activate_IRQ_rcvd; +extern int xpc_activate_IRQ_rcvd; +extern spinlock_t xpc_activate_IRQ_rcvd_lock; extern wait_queue_head_t xpc_activate_IRQ_wq; extern void *xpc_heartbeating_to_mask; +extern void *xpc_kzalloc_cacheline_aligned(size_t, gfp_t, void **); extern void xpc_activate_partition(struct xpc_partition *); extern void xpc_activate_kthreads(struct xpc_channel *, int); extern void xpc_create_kthreads(struct xpc_channel *, int, int); extern void xpc_disconnect_wait(int); +extern int (*xpc_setup_partitions_sn) (void); extern enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *, u64 *, unsigned long *, size_t *); -extern enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *); +extern int (*xpc_setup_rsvd_page_sn) (struct xpc_rsvd_page *); extern void (*xpc_heartbeat_init) (void); extern void (*xpc_heartbeat_exit) (void); extern void (*xpc_increment_heartbeat) (void); @@ -635,8 +729,8 @@ extern void (*xpc_online_heartbeat) (void); extern enum xp_retval (*xpc_get_remote_heartbeat) (struct xpc_partition *); extern enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *); extern u64 (*xpc_get_chctl_all_flags) (struct xpc_partition *); -extern enum xp_retval (*xpc_allocate_msgqueues) (struct xpc_channel *); -extern void (*xpc_free_msgqueues) (struct xpc_channel *); +extern enum xp_retval (*xpc_setup_msg_structures) (struct xpc_channel *); +extern void (*xpc_teardown_msg_structures) (struct xpc_channel *); extern void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *); extern void (*xpc_process_msg_chctl_flags) (struct xpc_partition *, int); extern int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *); @@ -647,9 +741,9 @@ extern void (*xpc_request_partition_reactivation) (struct xpc_partition *); extern void (*xpc_request_partition_deactivation) (struct xpc_partition *); extern void (*xpc_cancel_partition_deactivation_request) ( struct xpc_partition *); -extern void (*xpc_process_activate_IRQ_rcvd) (int); -extern enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *); -extern void (*xpc_teardown_infrastructure) (struct xpc_partition *); +extern void (*xpc_process_activate_IRQ_rcvd) (void); +extern enum xp_retval (*xpc_setup_ch_structures_sn) (struct xpc_partition *); +extern void (*xpc_teardown_ch_structures_sn) (struct xpc_partition *); extern void (*xpc_indicate_partition_engaged) (struct xpc_partition *); extern int (*xpc_partition_engaged) (short); @@ -665,6 +759,9 @@ extern void (*xpc_send_chctl_openrequest) (struct xpc_channel *, unsigned long *); extern void (*xpc_send_chctl_openreply) (struct xpc_channel *, unsigned long *); +extern void (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *, + unsigned long); + extern enum xp_retval (*xpc_send_msg) (struct xpc_channel *, u32, void *, u16, u8, xpc_notify_func, void *); extern void (*xpc_received_msg) (struct xpc_channel *, struct xpc_msg *); @@ -674,7 +771,7 @@ extern int xpc_init_sn2(void); extern void xpc_exit_sn2(void); /* found in xpc_uv.c */ -extern void xpc_init_uv(void); +extern int xpc_init_uv(void); extern void xpc_exit_uv(void); /* found in xpc_partition.c */ @@ -684,7 +781,8 @@ extern struct xpc_rsvd_page *xpc_rsvd_page; extern unsigned long *xpc_mach_nasids; extern struct xpc_partition *xpc_partitions; extern void *xpc_kmalloc_cacheline_aligned(size_t, gfp_t, void **); -extern struct xpc_rsvd_page *xpc_setup_rsvd_page(void); +extern int xpc_setup_rsvd_page(void); +extern void xpc_teardown_rsvd_page(void); extern int xpc_identify_activate_IRQ_sender(void); extern int xpc_partition_disengaged(struct xpc_partition *); extern enum xp_retval xpc_mark_partition_active(struct xpc_partition *); diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index 17ab75d69e8..73df9fb5ee6 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -39,7 +39,7 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) if (!(ch->flags & XPC_C_SETUP)) { spin_unlock_irqrestore(&ch->lock, *irq_flags); - ret = xpc_allocate_msgqueues(ch); + ret = xpc_setup_msg_structures(ch); spin_lock_irqsave(&ch->lock, *irq_flags); if (ret != xpSuccess) @@ -62,8 +62,6 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) if (!(ch->flags & XPC_C_ROPENREPLY)) return; - DBUG_ON(ch->remote_msgqueue_pa == 0); - ch->flags = (XPC_C_CONNECTED | XPC_C_SETUP); /* clear all else */ dev_info(xpc_chan, "channel %d to partition %d connected\n", @@ -134,13 +132,23 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) spin_lock_irqsave(&ch->lock, *irq_flags); } + DBUG_ON(atomic_read(&ch->n_to_notify) != 0); + /* it's now safe to free the channel's message queues */ - xpc_free_msgqueues(ch); + xpc_teardown_msg_structures(ch); + + ch->func = NULL; + ch->key = NULL; + ch->msg_size = 0; + ch->local_nentries = 0; + ch->remote_nentries = 0; + ch->kthreads_assigned_limit = 0; + ch->kthreads_idle_limit = 0; /* * Mark the channel disconnected and clear all other flags, including - * XPC_C_SETUP (because of call to xpc_free_msgqueues()) but not - * including XPC_C_WDISCONNECT (if it was set). + * XPC_C_SETUP (because of call to xpc_teardown_msg_structures()) but + * not including XPC_C_WDISCONNECT (if it was set). */ ch->flags = (XPC_C_DISCONNECTED | (ch->flags & XPC_C_WDISCONNECT)); @@ -395,7 +403,7 @@ again: DBUG_ON(args->remote_nentries == 0); ch->flags |= XPC_C_ROPENREPLY; - ch->remote_msgqueue_pa = args->local_msgqueue_pa; + xpc_save_remote_msgqueue_pa(ch, args->local_msgqueue_pa); if (args->local_nentries < ch->remote_nentries) { dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY: new " diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index b303c130bba..13ec4792899 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -141,8 +141,9 @@ static struct ctl_table_header *xpc_sysctl; /* non-zero if any remote partition disengage was timed out */ int xpc_disengage_timedout; -/* #of activate IRQs received */ -atomic_t xpc_activate_IRQ_rcvd = ATOMIC_INIT(0); +/* #of activate IRQs received and not yet processed */ +int xpc_activate_IRQ_rcvd; +DEFINE_SPINLOCK(xpc_activate_IRQ_rcvd_lock); /* IRQ handler notifies this wait queue on receipt of an IRQ */ DECLARE_WAIT_QUEUE_HEAD(xpc_activate_IRQ_wq); @@ -169,10 +170,11 @@ static struct notifier_block xpc_die_notifier = { .notifier_call = xpc_system_die, }; +int (*xpc_setup_partitions_sn) (void); enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *buf, u64 *cookie, unsigned long *rp_pa, size_t *len); -enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *rp); +int (*xpc_setup_rsvd_page_sn) (struct xpc_rsvd_page *rp); void (*xpc_heartbeat_init) (void); void (*xpc_heartbeat_exit) (void); void (*xpc_increment_heartbeat) (void); @@ -183,8 +185,8 @@ enum xp_retval (*xpc_get_remote_heartbeat) (struct xpc_partition *part); enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *part); void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *ch); u64 (*xpc_get_chctl_all_flags) (struct xpc_partition *part); -enum xp_retval (*xpc_allocate_msgqueues) (struct xpc_channel *ch); -void (*xpc_free_msgqueues) (struct xpc_channel *ch); +enum xp_retval (*xpc_setup_msg_structures) (struct xpc_channel *ch); +void (*xpc_teardown_msg_structures) (struct xpc_channel *ch); void (*xpc_process_msg_chctl_flags) (struct xpc_partition *part, int ch_number); int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *ch); struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *ch); @@ -196,9 +198,9 @@ void (*xpc_request_partition_reactivation) (struct xpc_partition *part); void (*xpc_request_partition_deactivation) (struct xpc_partition *part); void (*xpc_cancel_partition_deactivation_request) (struct xpc_partition *part); -void (*xpc_process_activate_IRQ_rcvd) (int n_IRQs_expected); -enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *part); -void (*xpc_teardown_infrastructure) (struct xpc_partition *part); +void (*xpc_process_activate_IRQ_rcvd) (void); +enum xp_retval (*xpc_setup_ch_structures_sn) (struct xpc_partition *part); +void (*xpc_teardown_ch_structures_sn) (struct xpc_partition *part); void (*xpc_indicate_partition_engaged) (struct xpc_partition *part); int (*xpc_partition_engaged) (short partid); @@ -215,6 +217,9 @@ void (*xpc_send_chctl_openrequest) (struct xpc_channel *ch, void (*xpc_send_chctl_openreply) (struct xpc_channel *ch, unsigned long *irq_flags); +void (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *ch, + unsigned long msgqueue_pa); + enum xp_retval (*xpc_send_msg) (struct xpc_channel *ch, u32 flags, void *payload, u16 payload_size, u8 notify_type, xpc_notify_func func, void *key); @@ -308,8 +313,6 @@ xpc_check_remote_hb(void) static int xpc_hb_checker(void *ignore) { - int last_IRQ_count = 0; - int new_IRQ_count; int force_IRQ = 0; /* this thread was marked active by xpc_hb_init() */ @@ -325,43 +328,37 @@ xpc_hb_checker(void *ignore) dev_dbg(xpc_part, "woke up with %d ticks rem; %d IRQs have " "been received\n", (int)(xpc_hb_check_timeout - jiffies), - atomic_read(&xpc_activate_IRQ_rcvd) - last_IRQ_count); + xpc_activate_IRQ_rcvd); /* checking of remote heartbeats is skewed by IRQ handling */ if (time_is_before_eq_jiffies(xpc_hb_check_timeout)) { + xpc_hb_check_timeout = jiffies + + (xpc_hb_check_interval * HZ); + dev_dbg(xpc_part, "checking remote heartbeats\n"); xpc_check_remote_hb(); /* - * We need to periodically recheck to ensure no - * IRQ/amo pairs have been missed. That check - * must always reset xpc_hb_check_timeout. + * On sn2 we need to periodically recheck to ensure no + * IRQ/amo pairs have been missed. */ - force_IRQ = 1; + if (is_shub()) + force_IRQ = 1; } /* check for outstanding IRQs */ - new_IRQ_count = atomic_read(&xpc_activate_IRQ_rcvd); - if (last_IRQ_count < new_IRQ_count || force_IRQ != 0) { + if (xpc_activate_IRQ_rcvd > 0 || force_IRQ != 0) { force_IRQ = 0; - - dev_dbg(xpc_part, "found an IRQ to process; will be " - "resetting xpc_hb_check_timeout\n"); - - xpc_process_activate_IRQ_rcvd(new_IRQ_count - - last_IRQ_count); - last_IRQ_count = new_IRQ_count; - - xpc_hb_check_timeout = jiffies + - (xpc_hb_check_interval * HZ); + dev_dbg(xpc_part, "processing activate IRQs " + "received\n"); + xpc_process_activate_IRQ_rcvd(); } /* wait for IRQ or timeout */ (void)wait_event_interruptible(xpc_activate_IRQ_wq, - (last_IRQ_count < atomic_read( - &xpc_activate_IRQ_rcvd) - || time_is_before_eq_jiffies( + (time_is_before_eq_jiffies( xpc_hb_check_timeout) || + xpc_activate_IRQ_rcvd > 0 || xpc_exiting)); } @@ -436,6 +433,153 @@ xpc_channel_mgr(struct xpc_partition *part) } } +/* + * Guarantee that the kzalloc'd memory is cacheline aligned. + */ +void * +xpc_kzalloc_cacheline_aligned(size_t size, gfp_t flags, void **base) +{ + /* see if kzalloc will give us cachline aligned memory by default */ + *base = kzalloc(size, flags); + if (*base == NULL) + return NULL; + + if ((u64)*base == L1_CACHE_ALIGN((u64)*base)) + return *base; + + kfree(*base); + + /* nope, we'll have to do it ourselves */ + *base = kzalloc(size + L1_CACHE_BYTES, flags); + if (*base == NULL) + return NULL; + + return (void *)L1_CACHE_ALIGN((u64)*base); +} + +/* + * Setup the channel structures necessary to support XPartition Communication + * between the specified remote partition and the local one. + */ +static enum xp_retval +xpc_setup_ch_structures(struct xpc_partition *part) +{ + enum xp_retval ret; + int ch_number; + struct xpc_channel *ch; + short partid = XPC_PARTID(part); + + /* + * Allocate all of the channel structures as a contiguous chunk of + * memory. + */ + DBUG_ON(part->channels != NULL); + part->channels = kzalloc(sizeof(struct xpc_channel) * XPC_MAX_NCHANNELS, + GFP_KERNEL); + if (part->channels == NULL) { + dev_err(xpc_chan, "can't get memory for channels\n"); + return xpNoMemory; + } + + /* allocate the remote open and close args */ + + part->remote_openclose_args = + xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE, + GFP_KERNEL, &part-> + remote_openclose_args_base); + if (part->remote_openclose_args == NULL) { + dev_err(xpc_chan, "can't get memory for remote connect args\n"); + ret = xpNoMemory; + goto out_1; + } + + part->chctl.all_flags = 0; + spin_lock_init(&part->chctl_lock); + + atomic_set(&part->channel_mgr_requests, 1); + init_waitqueue_head(&part->channel_mgr_wq); + + part->nchannels = XPC_MAX_NCHANNELS; + + atomic_set(&part->nchannels_active, 0); + atomic_set(&part->nchannels_engaged, 0); + + for (ch_number = 0; ch_number < part->nchannels; ch_number++) { + ch = &part->channels[ch_number]; + + ch->partid = partid; + ch->number = ch_number; + ch->flags = XPC_C_DISCONNECTED; + + atomic_set(&ch->kthreads_assigned, 0); + atomic_set(&ch->kthreads_idle, 0); + atomic_set(&ch->kthreads_active, 0); + + atomic_set(&ch->references, 0); + atomic_set(&ch->n_to_notify, 0); + + spin_lock_init(&ch->lock); + init_completion(&ch->wdisconnect_wait); + + atomic_set(&ch->n_on_msg_allocate_wq, 0); + init_waitqueue_head(&ch->msg_allocate_wq); + init_waitqueue_head(&ch->idle_wq); + } + + ret = xpc_setup_ch_structures_sn(part); + if (ret != xpSuccess) + goto out_2; + + /* + * With the setting of the partition setup_state to XPC_P_SS_SETUP, + * we're declaring that this partition is ready to go. + */ + part->setup_state = XPC_P_SS_SETUP; + + return xpSuccess; + + /* setup of ch structures failed */ +out_2: + kfree(part->remote_openclose_args_base); + part->remote_openclose_args = NULL; +out_1: + kfree(part->channels); + part->channels = NULL; + return ret; +} + +/* + * Teardown the channel structures necessary to support XPartition Communication + * between the specified remote partition and the local one. + */ +static void +xpc_teardown_ch_structures(struct xpc_partition *part) +{ + DBUG_ON(atomic_read(&part->nchannels_engaged) != 0); + DBUG_ON(atomic_read(&part->nchannels_active) != 0); + + /* + * Make this partition inaccessible to local processes by marking it + * as no longer setup. Then wait before proceeding with the teardown + * until all existing references cease. + */ + DBUG_ON(part->setup_state != XPC_P_SS_SETUP); + part->setup_state = XPC_P_SS_WTEARDOWN; + + wait_event(part->teardown_wq, (atomic_read(&part->references) == 0)); + + /* now we can begin tearing down the infrastructure */ + + xpc_teardown_ch_structures_sn(part); + + kfree(part->remote_openclose_args_base); + part->remote_openclose_args = NULL; + kfree(part->channels); + part->channels = NULL; + + part->setup_state = XPC_P_SS_TORNDOWN; +} + /* * When XPC HB determines that a partition has come up, it will create a new * kthread and that kthread will call this function to attempt to set up the @@ -476,7 +620,7 @@ xpc_activating(void *__partid) xpc_allow_hb(partid); - if (xpc_setup_infrastructure(part) == xpSuccess) { + if (xpc_setup_ch_structures(part) == xpSuccess) { (void)xpc_part_ref(part); /* this will always succeed */ if (xpc_make_first_contact(part) == xpSuccess) { @@ -486,7 +630,7 @@ xpc_activating(void *__partid) } xpc_part_deref(part); - xpc_teardown_infrastructure(part); + xpc_teardown_ch_structures(part); } xpc_disallow_hb(partid); @@ -806,6 +950,56 @@ xpc_disconnect_wait(int ch_number) } } +static int +xpc_setup_partitions(void) +{ + short partid; + struct xpc_partition *part; + + xpc_partitions = kzalloc(sizeof(struct xpc_partition) * + xp_max_npartitions, GFP_KERNEL); + if (xpc_partitions == NULL) { + dev_err(xpc_part, "can't get memory for partition structure\n"); + return -ENOMEM; + } + + /* + * The first few fields of each entry of xpc_partitions[] need to + * be initialized now so that calls to xpc_connect() and + * xpc_disconnect() can be made prior to the activation of any remote + * partition. NOTE THAT NONE OF THE OTHER FIELDS BELONGING TO THESE + * ENTRIES ARE MEANINGFUL UNTIL AFTER AN ENTRY'S CORRESPONDING + * PARTITION HAS BEEN ACTIVATED. + */ + for (partid = 0; partid < xp_max_npartitions; partid++) { + part = &xpc_partitions[partid]; + + DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part)); + + part->activate_IRQ_rcvd = 0; + spin_lock_init(&part->act_lock); + part->act_state = XPC_P_AS_INACTIVE; + XPC_SET_REASON(part, 0, 0); + + init_timer(&part->disengage_timer); + part->disengage_timer.function = + xpc_timeout_partition_disengage; + part->disengage_timer.data = (unsigned long)part; + + part->setup_state = XPC_P_SS_UNSET; + init_waitqueue_head(&part->teardown_wq); + atomic_set(&part->references, 0); + } + + return xpc_setup_partitions_sn(); +} + +static void +xpc_teardown_partitions(void) +{ + kfree(xpc_partitions); +} + static void xpc_do_exit(enum xp_retval reason) { @@ -892,8 +1086,7 @@ xpc_do_exit(enum xp_retval reason) DBUG_ON(xpc_any_partition_engaged()); DBUG_ON(xpc_any_hbs_allowed() != 0); - /* a zero timestamp indicates our rsvd page is not initialized */ - xpc_rsvd_page->ts_jiffies = 0; + xpc_teardown_rsvd_page(); if (reason == xpUnloading) { (void)unregister_die_notifier(&xpc_die_notifier); @@ -906,7 +1099,7 @@ xpc_do_exit(enum xp_retval reason) if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); - kfree(xpc_partitions); + xpc_teardown_partitions(); if (is_shub()) xpc_exit_sn2(); @@ -1062,8 +1255,6 @@ int __init xpc_init(void) { int ret; - short partid; - struct xpc_partition *part; struct task_struct *kthread; snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part"); @@ -1076,56 +1267,29 @@ xpc_init(void) * further to only support exactly 64 partitions on this * architecture, no less. */ - if (xp_max_npartitions != 64) - return -EINVAL; - - ret = xpc_init_sn2(); - if (ret != 0) - return ret; + if (xp_max_npartitions != 64) { + dev_err(xpc_part, "max #of partitions not set to 64\n"); + ret = -EINVAL; + } else { + ret = xpc_init_sn2(); + } } else if (is_uv()) { - xpc_init_uv(); + ret = xpc_init_uv(); } else { - return -ENODEV; + ret = -ENODEV; } - xpc_partitions = kzalloc(sizeof(struct xpc_partition) * - xp_max_npartitions, GFP_KERNEL); - if (xpc_partitions == NULL) { + if (ret != 0) + return ret; + + ret = xpc_setup_partitions(); + if (ret != 0) { dev_err(xpc_part, "can't get memory for partition structure\n"); - ret = -ENOMEM; goto out_1; } - /* - * The first few fields of each entry of xpc_partitions[] need to - * be initialized now so that calls to xpc_connect() and - * xpc_disconnect() can be made prior to the activation of any remote - * partition. NOTE THAT NONE OF THE OTHER FIELDS BELONGING TO THESE - * ENTRIES ARE MEANINGFUL UNTIL AFTER AN ENTRY'S CORRESPONDING - * PARTITION HAS BEEN ACTIVATED. - */ - for (partid = 0; partid < xp_max_npartitions; partid++) { - part = &xpc_partitions[partid]; - - DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part)); - - part->activate_IRQ_rcvd = 0; - spin_lock_init(&part->act_lock); - part->act_state = XPC_P_AS_INACTIVE; - XPC_SET_REASON(part, 0, 0); - - init_timer(&part->disengage_timer); - part->disengage_timer.function = - xpc_timeout_partition_disengage; - part->disengage_timer.data = (unsigned long)part; - - part->setup_state = XPC_P_SS_UNSET; - init_waitqueue_head(&part->teardown_wq); - atomic_set(&part->references, 0); - } - xpc_sysctl = register_sysctl_table(xpc_sys_dir); /* @@ -1133,10 +1297,9 @@ xpc_init(void) * other partitions to discover we are alive and establish initial * communications. */ - xpc_rsvd_page = xpc_setup_rsvd_page(); - if (xpc_rsvd_page == NULL) { + ret = xpc_setup_rsvd_page(); + if (ret != 0) { dev_err(xpc_part, "can't setup our reserved page\n"); - ret = -EBUSY; goto out_2; } @@ -1187,15 +1350,15 @@ xpc_init(void) /* initialization was not successful */ out_3: - /* a zero timestamp indicates our rsvd page is not initialized */ - xpc_rsvd_page->ts_jiffies = 0; + xpc_teardown_rsvd_page(); (void)unregister_die_notifier(&xpc_die_notifier); (void)unregister_reboot_notifier(&xpc_reboot_notifier); out_2: if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); - kfree(xpc_partitions); + + xpc_teardown_partitions(); out_1: if (is_shub()) xpc_exit_sn2(); diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index b5fb2164113..6722f6fe4dc 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -73,6 +73,12 @@ xpc_get_rsvd_page_pa(int nasid) while (1) { + /* !!! rp_pa will need to be _gpa on UV. + * ??? So do we save it into the architecture specific parts + * ??? of the xpc_partition structure? Do we rename this + * ??? function or have two versions? Rename rp_pa for UV to + * ??? rp_gpa? + */ ret = xpc_get_partition_rsvd_page_pa(buf, &cookie, &rp_pa, &len); @@ -118,9 +124,10 @@ xpc_get_rsvd_page_pa(int nasid) * other partitions to discover we are alive and establish initial * communications. */ -struct xpc_rsvd_page * +int xpc_setup_rsvd_page(void) { + int ret; struct xpc_rsvd_page *rp; unsigned long rp_pa; unsigned long new_ts_jiffies; @@ -132,7 +139,7 @@ xpc_setup_rsvd_page(void) preempt_enable(); if (rp_pa == 0) { dev_err(xpc_part, "SAL failed to locate the reserved page\n"); - return NULL; + return -ESRCH; } rp = (struct xpc_rsvd_page *)__va(rp_pa); @@ -146,7 +153,7 @@ xpc_setup_rsvd_page(void) dev_err(xpc_part, "the reserved page's partid of %d is outside " "supported range (< 0 || >= %d)\n", rp->SAL_partid, xp_max_npartitions); - return NULL; + return -EINVAL; } rp->version = XPC_RP_VERSION; @@ -165,8 +172,9 @@ xpc_setup_rsvd_page(void) xpc_part_nasids = XPC_RP_PART_NASIDS(rp); xpc_mach_nasids = XPC_RP_MACH_NASIDS(rp); - if (xpc_rsvd_page_init(rp) != xpSuccess) - return NULL; + ret = xpc_setup_rsvd_page_sn(rp); + if (ret != 0) + return ret; /* * Set timestamp of when reserved page was setup by XPC. @@ -178,7 +186,15 @@ xpc_setup_rsvd_page(void) new_ts_jiffies++; rp->ts_jiffies = new_ts_jiffies; - return rp; + xpc_rsvd_page = rp; + return 0; +} + +void +xpc_teardown_rsvd_page(void) +{ + /* a zero timestamp indicates our rsvd page is not initialized */ + xpc_rsvd_page->ts_jiffies = 0; } /* diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index d1ccadc0857..8b4b0653d9e 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -53,12 +53,19 @@ * Buffer used to store a local copy of portions of a remote partition's * reserved page (either its header and part_nasids mask, or its vars). */ -static char *xpc_remote_copy_buffer_sn2; static void *xpc_remote_copy_buffer_base_sn2; +static char *xpc_remote_copy_buffer_sn2; static struct xpc_vars_sn2 *xpc_vars_sn2; static struct xpc_vars_part_sn2 *xpc_vars_part_sn2; +static int +xpc_setup_partitions_sn_sn2(void) +{ + /* nothing needs to be done */ + return 0; +} + /* SH_IPI_ACCESS shub register value on startup */ static u64 xpc_sh1_IPI_access_sn2; static u64 xpc_sh2_IPI_access0_sn2; @@ -198,7 +205,12 @@ xpc_init_IRQ_amo_sn2(int index) static irqreturn_t xpc_handle_activate_IRQ_sn2(int irq, void *dev_id) { - atomic_inc(&xpc_activate_IRQ_rcvd); + unsigned long irq_flags; + + spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); + xpc_activate_IRQ_rcvd++; + spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); + wake_up_interruptible(&xpc_activate_IRQ_wq); return IRQ_HANDLED; } @@ -222,6 +234,7 @@ xpc_send_activate_IRQ_sn2(unsigned long amos_page_pa, int from_nasid, static void xpc_send_local_activate_IRQ_sn2(int from_nasid) { + unsigned long irq_flags; struct amo *amos = (struct amo *)__va(xpc_vars_sn2->amos_page_pa + (XPC_ACTIVATE_IRQ_AMOS_SN2 * sizeof(struct amo))); @@ -230,7 +243,10 @@ xpc_send_local_activate_IRQ_sn2(int from_nasid) FETCHOP_STORE_OP(TO_AMO((u64)&amos[BIT_WORD(from_nasid / 2)].variable), FETCHOP_OR, BIT_MASK(from_nasid / 2)); - atomic_inc(&xpc_activate_IRQ_rcvd); + spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); + xpc_activate_IRQ_rcvd++; + spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); + wake_up_interruptible(&xpc_activate_IRQ_wq); } @@ -375,7 +391,7 @@ static void xpc_send_chctl_closerequest_sn2(struct xpc_channel *ch, unsigned long *irq_flags) { - struct xpc_openclose_args *args = ch->local_openclose_args; + struct xpc_openclose_args *args = ch->sn.sn2.local_openclose_args; args->reason = ch->reason; XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_CLOSEREQUEST, irq_flags); @@ -390,7 +406,7 @@ xpc_send_chctl_closereply_sn2(struct xpc_channel *ch, unsigned long *irq_flags) static void xpc_send_chctl_openrequest_sn2(struct xpc_channel *ch, unsigned long *irq_flags) { - struct xpc_openclose_args *args = ch->local_openclose_args; + struct xpc_openclose_args *args = ch->sn.sn2.local_openclose_args; args->msg_size = ch->msg_size; args->local_nentries = ch->local_nentries; @@ -400,11 +416,11 @@ xpc_send_chctl_openrequest_sn2(struct xpc_channel *ch, unsigned long *irq_flags) static void xpc_send_chctl_openreply_sn2(struct xpc_channel *ch, unsigned long *irq_flags) { - struct xpc_openclose_args *args = ch->local_openclose_args; + struct xpc_openclose_args *args = ch->sn.sn2.local_openclose_args; args->remote_nentries = ch->remote_nentries; args->local_nentries = ch->local_nentries; - args->local_msgqueue_pa = xp_pa(ch->local_msgqueue); + args->local_msgqueue_pa = xp_pa(ch->sn.sn2.local_msgqueue); XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_OPENREPLY, irq_flags); } @@ -420,6 +436,13 @@ xpc_send_chctl_local_msgrequest_sn2(struct xpc_channel *ch) XPC_SEND_LOCAL_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_MSGREQUEST); } +static void +xpc_save_remote_msgqueue_pa_sn2(struct xpc_channel *ch, + unsigned long msgqueue_pa) +{ + ch->sn.sn2.remote_msgqueue_pa = msgqueue_pa; +} + /* * This next set of functions are used to keep track of when a partition is * potentially engaged in accessing memory belonging to another partition. @@ -489,6 +512,17 @@ xpc_indicate_partition_disengaged_sn2(struct xpc_partition *part) part_sn2->activate_IRQ_phys_cpuid); } +static void +xpc_assume_partition_disengaged_sn2(short partid) +{ + struct amo *amo = xpc_vars_sn2->amos_page + + XPC_ENGAGED_PARTITIONS_AMO_SN2; + + /* clear bit(s) based on partid mask in our partition's amo */ + FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, + ~BIT(partid)); +} + static int xpc_partition_engaged_sn2(short partid) { @@ -510,17 +544,6 @@ xpc_any_partition_engaged_sn2(void) return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) != 0; } -static void -xpc_assume_partition_disengaged_sn2(short partid) -{ - struct amo *amo = xpc_vars_sn2->amos_page + - XPC_ENGAGED_PARTITIONS_AMO_SN2; - - /* clear bit(s) based on partid mask in our partition's amo */ - FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND, - ~BIT(partid)); -} - /* original protection values for each node */ static u64 xpc_prot_vec_sn2[MAX_NUMNODES]; @@ -595,8 +618,8 @@ xpc_get_partition_rsvd_page_pa_sn2(void *buf, u64 *cookie, unsigned long *rp_pa, } -static enum xp_retval -xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) +static int +xpc_setup_rsvd_page_sn_sn2(struct xpc_rsvd_page *rp) { struct amo *amos_page; int i; @@ -627,7 +650,7 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) amos_page = (struct amo *)TO_AMO(uncached_alloc_page(0, 1)); if (amos_page == NULL) { dev_err(xpc_part, "can't allocate page of amos\n"); - return xpNoMemory; + return -ENOMEM; } /* @@ -639,7 +662,7 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) dev_err(xpc_part, "can't allow amo operations\n"); uncached_free_page(__IA64_UNCACHED_OFFSET | TO_PHYS((u64)amos_page), 1); - return ret; + return -EPERM; } } @@ -665,7 +688,7 @@ xpc_rsvd_page_init_sn2(struct xpc_rsvd_page *rp) (void)xpc_init_IRQ_amo_sn2(XPC_ENGAGED_PARTITIONS_AMO_SN2); (void)xpc_init_IRQ_amo_sn2(XPC_DEACTIVATE_REQUEST_AMO_SN2); - return xpSuccess; + return 0; } static void @@ -1082,10 +1105,19 @@ xpc_identify_activate_IRQ_sender_sn2(void) } static void -xpc_process_activate_IRQ_rcvd_sn2(int n_IRQs_expected) +xpc_process_activate_IRQ_rcvd_sn2(void) { + unsigned long irq_flags; + int n_IRQs_expected; int n_IRQs_detected; + DBUG_ON(xpc_activate_IRQ_rcvd == 0); + + spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); + n_IRQs_expected = xpc_activate_IRQ_rcvd; + xpc_activate_IRQ_rcvd = 0; + spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); + n_IRQs_detected = xpc_identify_activate_IRQ_sender_sn2(); if (n_IRQs_detected < n_IRQs_expected) { /* retry once to help avoid missing amo */ @@ -1094,116 +1126,63 @@ xpc_process_activate_IRQ_rcvd_sn2(int n_IRQs_expected) } /* - * Guarantee that the kzalloc'd memory is cacheline aligned. - */ -static void * -xpc_kzalloc_cacheline_aligned_sn2(size_t size, gfp_t flags, void **base) -{ - /* see if kzalloc will give us cachline aligned memory by default */ - *base = kzalloc(size, flags); - if (*base == NULL) - return NULL; - - if ((u64)*base == L1_CACHE_ALIGN((u64)*base)) - return *base; - - kfree(*base); - - /* nope, we'll have to do it ourselves */ - *base = kzalloc(size + L1_CACHE_BYTES, flags); - if (*base == NULL) - return NULL; - - return (void *)L1_CACHE_ALIGN((u64)*base); -} - -/* - * Setup the infrastructure necessary to support XPartition Communication - * between the specified remote partition and the local one. + * Setup the channel structures that are sn2 specific. */ static enum xp_retval -xpc_setup_infrastructure_sn2(struct xpc_partition *part) +xpc_setup_ch_structures_sn_sn2(struct xpc_partition *part) { struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; + struct xpc_channel_sn2 *ch_sn2; enum xp_retval retval; int ret; int cpuid; int ch_number; - struct xpc_channel *ch; struct timer_list *timer; short partid = XPC_PARTID(part); - /* - * Allocate all of the channel structures as a contiguous chunk of - * memory. - */ - DBUG_ON(part->channels != NULL); - part->channels = kzalloc(sizeof(struct xpc_channel) * XPC_MAX_NCHANNELS, - GFP_KERNEL); - if (part->channels == NULL) { - dev_err(xpc_chan, "can't get memory for channels\n"); - return xpNoMemory; - } - /* allocate all the required GET/PUT values */ part_sn2->local_GPs = - xpc_kzalloc_cacheline_aligned_sn2(XPC_GP_SIZE, GFP_KERNEL, - &part_sn2->local_GPs_base); + xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, GFP_KERNEL, + &part_sn2->local_GPs_base); if (part_sn2->local_GPs == NULL) { dev_err(xpc_chan, "can't get memory for local get/put " "values\n"); - retval = xpNoMemory; - goto out_1; + return xpNoMemory; } part_sn2->remote_GPs = - xpc_kzalloc_cacheline_aligned_sn2(XPC_GP_SIZE, GFP_KERNEL, - &part_sn2->remote_GPs_base); + xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, GFP_KERNEL, + &part_sn2->remote_GPs_base); if (part_sn2->remote_GPs == NULL) { dev_err(xpc_chan, "can't get memory for remote get/put " "values\n"); retval = xpNoMemory; - goto out_2; + goto out_1; } part_sn2->remote_GPs_pa = 0; /* allocate all the required open and close args */ - part->local_openclose_args = - xpc_kzalloc_cacheline_aligned_sn2(XPC_OPENCLOSE_ARGS_SIZE, - GFP_KERNEL, - &part->local_openclose_args_base); - if (part->local_openclose_args == NULL) { + part_sn2->local_openclose_args = + xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE, + GFP_KERNEL, &part_sn2-> + local_openclose_args_base); + if (part_sn2->local_openclose_args == NULL) { dev_err(xpc_chan, "can't get memory for local connect args\n"); retval = xpNoMemory; - goto out_3; - } - - part->remote_openclose_args = - xpc_kzalloc_cacheline_aligned_sn2(XPC_OPENCLOSE_ARGS_SIZE, - GFP_KERNEL, - &part->remote_openclose_args_base); - if (part->remote_openclose_args == NULL) { - dev_err(xpc_chan, "can't get memory for remote connect args\n"); - retval = xpNoMemory; - goto out_4; + goto out_2; } part_sn2->remote_openclose_args_pa = 0; part_sn2->local_chctl_amo_va = xpc_init_IRQ_amo_sn2(partid); - part->chctl.all_flags = 0; - spin_lock_init(&part->chctl_lock); part_sn2->notify_IRQ_nasid = 0; part_sn2->notify_IRQ_phys_cpuid = 0; part_sn2->remote_chctl_amo_va = NULL; - atomic_set(&part->channel_mgr_requests, 1); - init_waitqueue_head(&part->channel_mgr_wq); - sprintf(part_sn2->notify_IRQ_owner, "xpc%02d", partid); ret = request_irq(SGI_XPC_NOTIFY, xpc_handle_notify_IRQ_sn2, IRQF_SHARED, part_sn2->notify_IRQ_owner, @@ -1212,7 +1191,7 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) dev_err(xpc_chan, "can't register NOTIFY IRQ handler, " "errno=%d\n", -ret); retval = xpLackOfResources; - goto out_5; + goto out_3; } /* Setup a timer to check for dropped notify IRQs */ @@ -1224,44 +1203,16 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) timer->expires = jiffies + XPC_DROPPED_NOTIFY_IRQ_WAIT_INTERVAL; add_timer(timer); - part->nchannels = XPC_MAX_NCHANNELS; - - atomic_set(&part->nchannels_active, 0); - atomic_set(&part->nchannels_engaged, 0); - for (ch_number = 0; ch_number < part->nchannels; ch_number++) { - ch = &part->channels[ch_number]; - - ch->partid = partid; - ch->number = ch_number; - ch->flags = XPC_C_DISCONNECTED; - - ch->sn.sn2.local_GP = &part_sn2->local_GPs[ch_number]; - ch->local_openclose_args = - &part->local_openclose_args[ch_number]; - - atomic_set(&ch->kthreads_assigned, 0); - atomic_set(&ch->kthreads_idle, 0); - atomic_set(&ch->kthreads_active, 0); + ch_sn2 = &part->channels[ch_number].sn.sn2; - atomic_set(&ch->references, 0); - atomic_set(&ch->n_to_notify, 0); + ch_sn2->local_GP = &part_sn2->local_GPs[ch_number]; + ch_sn2->local_openclose_args = + &part_sn2->local_openclose_args[ch_number]; - spin_lock_init(&ch->lock); - mutex_init(&ch->sn.sn2.msg_to_pull_mutex); - init_completion(&ch->wdisconnect_wait); - - atomic_set(&ch->n_on_msg_allocate_wq, 0); - init_waitqueue_head(&ch->msg_allocate_wq); - init_waitqueue_head(&ch->idle_wq); + mutex_init(&ch_sn2->msg_to_pull_mutex); } - /* - * With the setting of the partition setup_state to XPC_P_SS_SETUP, - * we're declaring that this partition is ready to go. - */ - part->setup_state = XPC_P_SS_SETUP; - /* * Setup the per partition specific variables required by the * remote partition to establish channel connections with us. @@ -1271,7 +1222,7 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) */ xpc_vars_part_sn2[partid].GPs_pa = xp_pa(part_sn2->local_GPs); xpc_vars_part_sn2[partid].openclose_args_pa = - xp_pa(part->local_openclose_args); + xp_pa(part_sn2->local_openclose_args); xpc_vars_part_sn2[partid].chctl_amo_pa = xp_pa(part_sn2->local_chctl_amo_va); cpuid = raw_smp_processor_id(); /* any CPU in this partition will do */ @@ -1279,80 +1230,48 @@ xpc_setup_infrastructure_sn2(struct xpc_partition *part) xpc_vars_part_sn2[partid].notify_IRQ_phys_cpuid = cpu_physical_id(cpuid); xpc_vars_part_sn2[partid].nchannels = part->nchannels; - xpc_vars_part_sn2[partid].magic = XPC_VP_MAGIC1; + xpc_vars_part_sn2[partid].magic = XPC_VP_MAGIC1_SN2; return xpSuccess; - /* setup of infrastructure failed */ -out_5: - kfree(part->remote_openclose_args_base); - part->remote_openclose_args = NULL; -out_4: - kfree(part->local_openclose_args_base); - part->local_openclose_args = NULL; + /* setup of ch structures failed */ out_3: + kfree(part_sn2->local_openclose_args_base); + part_sn2->local_openclose_args = NULL; +out_2: kfree(part_sn2->remote_GPs_base); part_sn2->remote_GPs = NULL; -out_2: +out_1: kfree(part_sn2->local_GPs_base); part_sn2->local_GPs = NULL; -out_1: - kfree(part->channels); - part->channels = NULL; return retval; } /* - * Teardown the infrastructure necessary to support XPartition Communication - * between the specified remote partition and the local one. + * Teardown the channel structures that are sn2 specific. */ static void -xpc_teardown_infrastructure_sn2(struct xpc_partition *part) +xpc_teardown_ch_structures_sn_sn2(struct xpc_partition *part) { struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2; short partid = XPC_PARTID(part); /* - * We start off by making this partition inaccessible to local - * processes by marking it as no longer setup. Then we make it - * inaccessible to remote processes by clearing the XPC per partition - * specific variable's magic # (which indicates that these variables - * are no longer valid) and by ignoring all XPC notify IRQs sent to - * this partition. + * Indicate that the variables specific to the remote partition are no + * longer available for its use. */ - - DBUG_ON(atomic_read(&part->nchannels_engaged) != 0); - DBUG_ON(atomic_read(&part->nchannels_active) != 0); - DBUG_ON(part->setup_state != XPC_P_SS_SETUP); - part->setup_state = XPC_P_SS_WTEARDOWN; - xpc_vars_part_sn2[partid].magic = 0; - free_irq(SGI_XPC_NOTIFY, (void *)(u64)partid); - - /* - * Before proceeding with the teardown we have to wait until all - * existing references cease. - */ - wait_event(part->teardown_wq, (atomic_read(&part->references) == 0)); - - /* now we can begin tearing down the infrastructure */ - - part->setup_state = XPC_P_SS_TORNDOWN; - /* in case we've still got outstanding timers registered... */ del_timer_sync(&part_sn2->dropped_notify_IRQ_timer); + free_irq(SGI_XPC_NOTIFY, (void *)(u64)partid); - kfree(part->remote_openclose_args_base); - part->remote_openclose_args = NULL; - kfree(part->local_openclose_args_base); - part->local_openclose_args = NULL; + kfree(part_sn2->local_openclose_args_base); + part_sn2->local_openclose_args = NULL; kfree(part_sn2->remote_GPs_base); part_sn2->remote_GPs = NULL; kfree(part_sn2->local_GPs_base); part_sn2->local_GPs = NULL; - kfree(part->channels); - part->channels = NULL; part_sn2->local_chctl_amo_va = NULL; } @@ -1429,8 +1348,8 @@ xpc_pull_remote_vars_part_sn2(struct xpc_partition *part) /* see if they've been set up yet */ - if (pulled_entry->magic != XPC_VP_MAGIC1 && - pulled_entry->magic != XPC_VP_MAGIC2) { + if (pulled_entry->magic != XPC_VP_MAGIC1_SN2 && + pulled_entry->magic != XPC_VP_MAGIC2_SN2) { if (pulled_entry->magic != 0) { dev_dbg(xpc_chan, "partition %d's XPC vars_part for " @@ -1443,7 +1362,7 @@ xpc_pull_remote_vars_part_sn2(struct xpc_partition *part) return xpRetry; } - if (xpc_vars_part_sn2[partid].magic == XPC_VP_MAGIC1) { + if (xpc_vars_part_sn2[partid].magic == XPC_VP_MAGIC1_SN2) { /* validate the variables */ @@ -1473,10 +1392,10 @@ xpc_pull_remote_vars_part_sn2(struct xpc_partition *part) /* let the other side know that we've pulled their variables */ - xpc_vars_part_sn2[partid].magic = XPC_VP_MAGIC2; + xpc_vars_part_sn2[partid].magic = XPC_VP_MAGIC2_SN2; } - if (pulled_entry->magic == XPC_VP_MAGIC1) + if (pulled_entry->magic == XPC_VP_MAGIC1_SN2) return xpRetry; return xpSuccess; @@ -1605,6 +1524,7 @@ xpc_get_chctl_all_flags_sn2(struct xpc_partition *part) static enum xp_retval xpc_allocate_local_msgqueue_sn2(struct xpc_channel *ch) { + struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; unsigned long irq_flags; int nentries; size_t nbytes; @@ -1612,17 +1532,17 @@ xpc_allocate_local_msgqueue_sn2(struct xpc_channel *ch) for (nentries = ch->local_nentries; nentries > 0; nentries--) { nbytes = nentries * ch->msg_size; - ch->local_msgqueue = - xpc_kzalloc_cacheline_aligned_sn2(nbytes, GFP_KERNEL, - &ch->local_msgqueue_base); - if (ch->local_msgqueue == NULL) + ch_sn2->local_msgqueue = + xpc_kzalloc_cacheline_aligned(nbytes, GFP_KERNEL, + &ch_sn2->local_msgqueue_base); + if (ch_sn2->local_msgqueue == NULL) continue; nbytes = nentries * sizeof(struct xpc_notify); - ch->notify_queue = kzalloc(nbytes, GFP_KERNEL); - if (ch->notify_queue == NULL) { - kfree(ch->local_msgqueue_base); - ch->local_msgqueue = NULL; + ch_sn2->notify_queue = kzalloc(nbytes, GFP_KERNEL); + if (ch_sn2->notify_queue == NULL) { + kfree(ch_sn2->local_msgqueue_base); + ch_sn2->local_msgqueue = NULL; continue; } @@ -1649,6 +1569,7 @@ xpc_allocate_local_msgqueue_sn2(struct xpc_channel *ch) static enum xp_retval xpc_allocate_remote_msgqueue_sn2(struct xpc_channel *ch) { + struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; unsigned long irq_flags; int nentries; size_t nbytes; @@ -1658,10 +1579,10 @@ xpc_allocate_remote_msgqueue_sn2(struct xpc_channel *ch) for (nentries = ch->remote_nentries; nentries > 0; nentries--) { nbytes = nentries * ch->msg_size; - ch->remote_msgqueue = - xpc_kzalloc_cacheline_aligned_sn2(nbytes, GFP_KERNEL, - &ch->remote_msgqueue_base); - if (ch->remote_msgqueue == NULL) + ch_sn2->remote_msgqueue = + xpc_kzalloc_cacheline_aligned(nbytes, GFP_KERNEL, &ch_sn2-> + remote_msgqueue_base); + if (ch_sn2->remote_msgqueue == NULL) continue; spin_lock_irqsave(&ch->lock, irq_flags); @@ -1687,8 +1608,9 @@ xpc_allocate_remote_msgqueue_sn2(struct xpc_channel *ch) * Note: Assumes all of the channel sizes are filled in. */ static enum xp_retval -xpc_allocate_msgqueues_sn2(struct xpc_channel *ch) +xpc_setup_msg_structures_sn2(struct xpc_channel *ch) { + struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; enum xp_retval ret; DBUG_ON(ch->flags & XPC_C_SETUP); @@ -1698,10 +1620,10 @@ xpc_allocate_msgqueues_sn2(struct xpc_channel *ch) ret = xpc_allocate_remote_msgqueue_sn2(ch); if (ret != xpSuccess) { - kfree(ch->local_msgqueue_base); - ch->local_msgqueue = NULL; - kfree(ch->notify_queue); - ch->notify_queue = NULL; + kfree(ch_sn2->local_msgqueue_base); + ch_sn2->local_msgqueue = NULL; + kfree(ch_sn2->notify_queue); + ch_sn2->notify_queue = NULL; } } return ret; @@ -1715,21 +1637,13 @@ xpc_allocate_msgqueues_sn2(struct xpc_channel *ch) * they're cleared when XPC_C_DISCONNECTED is cleared. */ static void -xpc_free_msgqueues_sn2(struct xpc_channel *ch) +xpc_teardown_msg_structures_sn2(struct xpc_channel *ch) { struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; DBUG_ON(!spin_is_locked(&ch->lock)); - DBUG_ON(atomic_read(&ch->n_to_notify) != 0); - ch->remote_msgqueue_pa = 0; - ch->func = NULL; - ch->key = NULL; - ch->msg_size = 0; - ch->local_nentries = 0; - ch->remote_nentries = 0; - ch->kthreads_assigned_limit = 0; - ch->kthreads_idle_limit = 0; + ch_sn2->remote_msgqueue_pa = 0; ch_sn2->local_GP->get = 0; ch_sn2->local_GP->put = 0; @@ -1745,12 +1659,12 @@ xpc_free_msgqueues_sn2(struct xpc_channel *ch) dev_dbg(xpc_chan, "ch->flags=0x%x, partid=%d, channel=%d\n", ch->flags, ch->partid, ch->number); - kfree(ch->local_msgqueue_base); - ch->local_msgqueue = NULL; - kfree(ch->remote_msgqueue_base); - ch->remote_msgqueue = NULL; - kfree(ch->notify_queue); - ch->notify_queue = NULL; + kfree(ch_sn2->local_msgqueue_base); + ch_sn2->local_msgqueue = NULL; + kfree(ch_sn2->remote_msgqueue_base); + ch_sn2->remote_msgqueue = NULL; + kfree(ch_sn2->notify_queue); + ch_sn2->notify_queue = NULL; } } @@ -1766,7 +1680,7 @@ xpc_notify_senders_sn2(struct xpc_channel *ch, enum xp_retval reason, s64 put) while (++get < put && atomic_read(&ch->n_to_notify) > 0) { - notify = &ch->notify_queue[get % ch->local_nentries]; + notify = &ch->sn.sn2.notify_queue[get % ch->local_nentries]; /* * See if the notify entry indicates it was associated with @@ -1818,7 +1732,7 @@ xpc_clear_local_msgqueue_flags_sn2(struct xpc_channel *ch) get = ch_sn2->w_remote_GP.get; do { - msg = (struct xpc_msg *)((u64)ch->local_msgqueue + + msg = (struct xpc_msg *)((u64)ch_sn2->local_msgqueue + (get % ch->local_nentries) * ch->msg_size); msg->flags = 0; @@ -1837,7 +1751,7 @@ xpc_clear_remote_msgqueue_flags_sn2(struct xpc_channel *ch) put = ch_sn2->w_remote_GP.put; do { - msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + + msg = (struct xpc_msg *)((u64)ch_sn2->remote_msgqueue + (put % ch->remote_nentries) * ch->msg_size); msg->flags = 0; @@ -1976,8 +1890,9 @@ xpc_pull_remote_msg_sn2(struct xpc_channel *ch, s64 get) } msg_offset = msg_index * ch->msg_size; - msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + msg_offset); - remote_msg_pa = ch->remote_msgqueue_pa + msg_offset; + msg = (struct xpc_msg *)((u64)ch_sn2->remote_msgqueue + + msg_offset); + remote_msg_pa = ch_sn2->remote_msgqueue_pa + msg_offset; ret = xpc_pull_remote_cachelines_sn2(part, msg, remote_msg_pa, nmsgs * ch->msg_size); @@ -2001,7 +1916,7 @@ xpc_pull_remote_msg_sn2(struct xpc_channel *ch, s64 get) /* return the message we were looking for */ msg_offset = (get % ch->remote_nentries) * ch->msg_size; - msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + msg_offset); + msg = (struct xpc_msg *)((u64)ch_sn2->remote_msgqueue + msg_offset); return msg; } @@ -2080,7 +1995,7 @@ xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put) if (put == ch_sn2->w_local_GP.put) break; - msg = (struct xpc_msg *)((u64)ch->local_msgqueue + + msg = (struct xpc_msg *)((u64)ch_sn2->local_msgqueue + (put % ch->local_nentries) * ch->msg_size); @@ -2182,7 +2097,7 @@ xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags, } /* get the message's address and initialize it */ - msg = (struct xpc_msg *)((u64)ch->local_msgqueue + + msg = (struct xpc_msg *)((u64)ch_sn2->local_msgqueue + (put % ch->local_nentries) * ch->msg_size); DBUG_ON(msg->flags != 0); @@ -2207,6 +2122,7 @@ xpc_send_msg_sn2(struct xpc_channel *ch, u32 flags, void *payload, void *key) { enum xp_retval ret = xpSuccess; + struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; struct xpc_msg *msg = msg; struct xpc_notify *notify = notify; s64 msg_number; @@ -2243,7 +2159,7 @@ xpc_send_msg_sn2(struct xpc_channel *ch, u32 flags, void *payload, atomic_inc(&ch->n_to_notify); - notify = &ch->notify_queue[msg_number % ch->local_nentries]; + notify = &ch_sn2->notify_queue[msg_number % ch->local_nentries]; notify->func = func; notify->key = key; notify->type = notify_type; @@ -2279,7 +2195,7 @@ xpc_send_msg_sn2(struct xpc_channel *ch, u32 flags, void *payload, /* see if the message is next in line to be sent, if so send it */ - put = ch->sn.sn2.local_GP->put; + put = ch_sn2->local_GP->put; if (put == msg_number) xpc_send_msgs_sn2(ch, put); @@ -2307,7 +2223,7 @@ xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) if (get == ch_sn2->w_local_GP.get) break; - msg = (struct xpc_msg *)((u64)ch->remote_msgqueue + + msg = (struct xpc_msg *)((u64)ch_sn2->remote_msgqueue + (get % ch->remote_nentries) * ch->msg_size); @@ -2385,8 +2301,9 @@ xpc_init_sn2(void) int ret; size_t buf_size; + xpc_setup_partitions_sn = xpc_setup_partitions_sn_sn2; xpc_get_partition_rsvd_page_pa = xpc_get_partition_rsvd_page_pa_sn2; - xpc_rsvd_page_init = xpc_rsvd_page_init_sn2; + xpc_setup_rsvd_page_sn = xpc_setup_rsvd_page_sn_sn2; xpc_increment_heartbeat = xpc_increment_heartbeat_sn2; xpc_offline_heartbeat = xpc_offline_heartbeat_sn2; xpc_online_heartbeat = xpc_online_heartbeat_sn2; @@ -2403,29 +2320,33 @@ xpc_init_sn2(void) xpc_cancel_partition_deactivation_request_sn2; xpc_process_activate_IRQ_rcvd = xpc_process_activate_IRQ_rcvd_sn2; - xpc_setup_infrastructure = xpc_setup_infrastructure_sn2; - xpc_teardown_infrastructure = xpc_teardown_infrastructure_sn2; + xpc_setup_ch_structures_sn = xpc_setup_ch_structures_sn_sn2; + xpc_teardown_ch_structures_sn = xpc_teardown_ch_structures_sn_sn2; xpc_make_first_contact = xpc_make_first_contact_sn2; + xpc_get_chctl_all_flags = xpc_get_chctl_all_flags_sn2; - xpc_allocate_msgqueues = xpc_allocate_msgqueues_sn2; - xpc_free_msgqueues = xpc_free_msgqueues_sn2; + xpc_send_chctl_closerequest = xpc_send_chctl_closerequest_sn2; + xpc_send_chctl_closereply = xpc_send_chctl_closereply_sn2; + xpc_send_chctl_openrequest = xpc_send_chctl_openrequest_sn2; + xpc_send_chctl_openreply = xpc_send_chctl_openreply_sn2; + + xpc_save_remote_msgqueue_pa = xpc_save_remote_msgqueue_pa_sn2; + + xpc_setup_msg_structures = xpc_setup_msg_structures_sn2; + xpc_teardown_msg_structures = xpc_teardown_msg_structures_sn2; + xpc_notify_senders_of_disconnect = xpc_notify_senders_of_disconnect_sn2; xpc_process_msg_chctl_flags = xpc_process_msg_chctl_flags_sn2; xpc_n_of_deliverable_msgs = xpc_n_of_deliverable_msgs_sn2; xpc_get_deliverable_msg = xpc_get_deliverable_msg_sn2; xpc_indicate_partition_engaged = xpc_indicate_partition_engaged_sn2; - xpc_partition_engaged = xpc_partition_engaged_sn2; - xpc_any_partition_engaged = xpc_any_partition_engaged_sn2; xpc_indicate_partition_disengaged = xpc_indicate_partition_disengaged_sn2; + xpc_partition_engaged = xpc_partition_engaged_sn2; + xpc_any_partition_engaged = xpc_any_partition_engaged_sn2; xpc_assume_partition_disengaged = xpc_assume_partition_disengaged_sn2; - xpc_send_chctl_closerequest = xpc_send_chctl_closerequest_sn2; - xpc_send_chctl_closereply = xpc_send_chctl_closereply_sn2; - xpc_send_chctl_openrequest = xpc_send_chctl_openrequest_sn2; - xpc_send_chctl_openreply = xpc_send_chctl_openreply_sn2; - xpc_send_msg = xpc_send_msg_sn2; xpc_received_msg = xpc_received_msg_sn2; diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index c2d4ddd6e95..689cb5c68cc 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c @@ -14,41 +14,528 @@ */ #include +#include +#include +#include +#include #include +#include "../sgi-gru/gru.h" #include "../sgi-gru/grukservices.h" #include "xpc.h" +static atomic64_t xpc_heartbeat_uv; static DECLARE_BITMAP(xpc_heartbeating_to_mask_uv, XP_MAX_NPARTITIONS_UV); -static void *xpc_activate_mq; +#define XPC_ACTIVATE_MSG_SIZE_UV (1 * GRU_CACHE_LINE_BYTES) +#define XPC_NOTIFY_MSG_SIZE_UV (2 * GRU_CACHE_LINE_BYTES) + +#define XPC_ACTIVATE_MQ_SIZE_UV (4 * XP_MAX_NPARTITIONS_UV * \ + XPC_ACTIVATE_MSG_SIZE_UV) +#define XPC_NOTIFY_MQ_SIZE_UV (4 * XP_MAX_NPARTITIONS_UV * \ + XPC_NOTIFY_MSG_SIZE_UV) + +static void *xpc_activate_mq_uv; +static void *xpc_notify_mq_uv; + +static int +xpc_setup_partitions_sn_uv(void) +{ + short partid; + struct xpc_partition_uv *part_uv; + + for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) { + part_uv = &xpc_partitions[partid].sn.uv; + + spin_lock_init(&part_uv->flags_lock); + part_uv->remote_act_state = XPC_P_AS_INACTIVE; + } + return 0; +} + +static void * +xpc_create_gru_mq_uv(unsigned int mq_size, int cpuid, unsigned int irq, + irq_handler_t irq_handler) +{ + int ret; + int nid; + int mq_order; + struct page *page; + void *mq; + + nid = cpu_to_node(cpuid); + mq_order = get_order(mq_size); + page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE, + mq_order); + if (page == NULL) + return NULL; + + mq = page_address(page); + ret = gru_create_message_queue(mq, mq_size); + if (ret != 0) { + dev_err(xpc_part, "gru_create_message_queue() returned " + "error=%d\n", ret); + free_pages((unsigned long)mq, mq_order); + return NULL; + } + + /* !!! Need to do some other things to set up IRQ */ + + ret = request_irq(irq, irq_handler, 0, "xpc", NULL); + if (ret != 0) { + dev_err(xpc_part, "request_irq(irq=%d) returned error=%d\n", + irq, ret); + free_pages((unsigned long)mq, mq_order); + return NULL; + } + + /* !!! enable generation of irq when GRU mq op occurs to this mq */ + + /* ??? allow other partitions to access GRU mq? */ + + return mq; +} static void -xpc_send_local_activate_IRQ_uv(struct xpc_partition *part) +xpc_destroy_gru_mq_uv(void *mq, unsigned int mq_size, unsigned int irq) +{ + /* ??? disallow other partitions to access GRU mq? */ + + /* !!! disable generation of irq when GRU mq op occurs to this mq */ + + free_irq(irq, NULL); + + free_pages((unsigned long)mq, get_order(mq_size)); +} + +static enum xp_retval +xpc_send_gru_msg(unsigned long mq_gpa, void *msg, size_t msg_size) { + enum xp_retval xp_ret; + int ret; + + while (1) { + ret = gru_send_message_gpa(mq_gpa, msg, msg_size); + if (ret == MQE_OK) { + xp_ret = xpSuccess; + break; + } + + if (ret == MQE_QUEUE_FULL) { + dev_dbg(xpc_chan, "gru_send_message_gpa() returned " + "error=MQE_QUEUE_FULL\n"); + /* !!! handle QLimit reached; delay & try again */ + /* ??? Do we add a limit to the number of retries? */ + (void)msleep_interruptible(10); + } else if (ret == MQE_CONGESTION) { + dev_dbg(xpc_chan, "gru_send_message_gpa() returned " + "error=MQE_CONGESTION\n"); + /* !!! handle LB Overflow; simply try again */ + /* ??? Do we add a limit to the number of retries? */ + } else { + /* !!! Currently this is MQE_UNEXPECTED_CB_ERR */ + dev_err(xpc_chan, "gru_send_message_gpa() returned " + "error=%d\n", ret); + xp_ret = xpGruSendMqError; + break; + } + } + return xp_ret; +} + +static void +xpc_process_activate_IRQ_rcvd_uv(void) +{ + unsigned long irq_flags; + short partid; + struct xpc_partition *part; + u8 act_state_req; + + DBUG_ON(xpc_activate_IRQ_rcvd == 0); + + spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); + for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) { + part = &xpc_partitions[partid]; + + if (part->sn.uv.act_state_req == 0) + continue; + + xpc_activate_IRQ_rcvd--; + BUG_ON(xpc_activate_IRQ_rcvd < 0); + + act_state_req = part->sn.uv.act_state_req; + part->sn.uv.act_state_req = 0; + spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); + + if (act_state_req == XPC_P_ASR_ACTIVATE_UV) { + if (part->act_state == XPC_P_AS_INACTIVE) + xpc_activate_partition(part); + else if (part->act_state == XPC_P_AS_DEACTIVATING) + XPC_DEACTIVATE_PARTITION(part, xpReactivating); + + } else if (act_state_req == XPC_P_ASR_REACTIVATE_UV) { + if (part->act_state == XPC_P_AS_INACTIVE) + xpc_activate_partition(part); + else + XPC_DEACTIVATE_PARTITION(part, xpReactivating); + + } else if (act_state_req == XPC_P_ASR_DEACTIVATE_UV) { + XPC_DEACTIVATE_PARTITION(part, part->sn.uv.reason); + + } else { + BUG(); + } + + spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); + if (xpc_activate_IRQ_rcvd == 0) + break; + } + spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); + +} + +static irqreturn_t +xpc_handle_activate_IRQ_uv(int irq, void *dev_id) +{ + unsigned long irq_flags; + struct xpc_activate_mq_msghdr_uv *msg_hdr; + short partid; + struct xpc_partition *part; + struct xpc_partition_uv *part_uv; + struct xpc_openclose_args *args; + int wakeup_hb_checker = 0; + + while ((msg_hdr = gru_get_next_message(xpc_activate_mq_uv)) != NULL) { + + partid = msg_hdr->partid; + if (partid < 0 || partid >= XP_MAX_NPARTITIONS_UV) { + dev_err(xpc_part, "xpc_handle_activate_IRQ_uv() invalid" + "partid=0x%x passed in message\n", partid); + gru_free_message(xpc_activate_mq_uv, msg_hdr); + continue; + } + part = &xpc_partitions[partid]; + part_uv = &part->sn.uv; + + part_uv->remote_act_state = msg_hdr->act_state; + + switch (msg_hdr->type) { + case XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV: + /* syncing of remote_act_state was just done above */ + break; + + case XPC_ACTIVATE_MQ_MSG_INC_HEARTBEAT_UV: { + struct xpc_activate_mq_msg_heartbeat_req_uv *msg; + + msg = (struct xpc_activate_mq_msg_heartbeat_req_uv *) + msg_hdr; + part_uv->heartbeat = msg->heartbeat; + break; + } + case XPC_ACTIVATE_MQ_MSG_OFFLINE_HEARTBEAT_UV: { + struct xpc_activate_mq_msg_heartbeat_req_uv *msg; + + msg = (struct xpc_activate_mq_msg_heartbeat_req_uv *) + msg_hdr; + part_uv->heartbeat = msg->heartbeat; + spin_lock_irqsave(&part_uv->flags_lock, irq_flags); + part_uv->flags |= XPC_P_HEARTBEAT_OFFLINE_UV; + spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); + break; + } + case XPC_ACTIVATE_MQ_MSG_ONLINE_HEARTBEAT_UV: { + struct xpc_activate_mq_msg_heartbeat_req_uv *msg; + + msg = (struct xpc_activate_mq_msg_heartbeat_req_uv *) + msg_hdr; + part_uv->heartbeat = msg->heartbeat; + spin_lock_irqsave(&part_uv->flags_lock, irq_flags); + part_uv->flags &= ~XPC_P_HEARTBEAT_OFFLINE_UV; + spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); + break; + } + case XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV: { + struct xpc_activate_mq_msg_activate_req_uv *msg; + + /* + * ??? Do we deal here with ts_jiffies being different + * ??? if act_state != XPC_P_AS_INACTIVE instead of + * ??? below? + */ + msg = (struct xpc_activate_mq_msg_activate_req_uv *) + msg_hdr; + spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, + irq_flags); + if (part_uv->act_state_req == 0) + xpc_activate_IRQ_rcvd++; + part_uv->act_state_req = XPC_P_ASR_ACTIVATE_UV; + part->remote_rp_pa = msg->rp_gpa; /* !!! _pa is _gpa */ + part->remote_rp_ts_jiffies = msg_hdr->rp_ts_jiffies; + part_uv->remote_activate_mq_gpa = msg->activate_mq_gpa; + spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, + irq_flags); + wakeup_hb_checker++; + break; + } + case XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV: { + struct xpc_activate_mq_msg_deactivate_req_uv *msg; + + msg = (struct xpc_activate_mq_msg_deactivate_req_uv *) + msg_hdr; + spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, + irq_flags); + if (part_uv->act_state_req == 0) + xpc_activate_IRQ_rcvd++; + part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV; + part_uv->reason = msg->reason; + spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, + irq_flags); + wakeup_hb_checker++; + break; + } + case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV: { + struct xpc_activate_mq_msg_chctl_closerequest_uv *msg; + + msg = (struct xpc_activate_mq_msg_chctl_closerequest_uv + *)msg_hdr; + args = &part->remote_openclose_args[msg->ch_number]; + args->reason = msg->reason; + + spin_lock_irqsave(&part->chctl_lock, irq_flags); + part->chctl.flags[msg->ch_number] |= + XPC_CHCTL_CLOSEREQUEST; + spin_unlock_irqrestore(&part->chctl_lock, irq_flags); + + xpc_wakeup_channel_mgr(part); + break; + } + case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV: { + struct xpc_activate_mq_msg_chctl_closereply_uv *msg; + + msg = (struct xpc_activate_mq_msg_chctl_closereply_uv *) + msg_hdr; + + spin_lock_irqsave(&part->chctl_lock, irq_flags); + part->chctl.flags[msg->ch_number] |= + XPC_CHCTL_CLOSEREPLY; + spin_unlock_irqrestore(&part->chctl_lock, irq_flags); + + xpc_wakeup_channel_mgr(part); + break; + } + case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV: { + struct xpc_activate_mq_msg_chctl_openrequest_uv *msg; + + msg = (struct xpc_activate_mq_msg_chctl_openrequest_uv + *)msg_hdr; + args = &part->remote_openclose_args[msg->ch_number]; + args->msg_size = msg->msg_size; + args->local_nentries = msg->local_nentries; + + spin_lock_irqsave(&part->chctl_lock, irq_flags); + part->chctl.flags[msg->ch_number] |= + XPC_CHCTL_OPENREQUEST; + spin_unlock_irqrestore(&part->chctl_lock, irq_flags); + + xpc_wakeup_channel_mgr(part); + break; + } + case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV: { + struct xpc_activate_mq_msg_chctl_openreply_uv *msg; + + msg = (struct xpc_activate_mq_msg_chctl_openreply_uv *) + msg_hdr; + args = &part->remote_openclose_args[msg->ch_number]; + args->remote_nentries = msg->remote_nentries; + args->local_nentries = msg->local_nentries; + args->local_msgqueue_pa = msg->local_notify_mq_gpa; + + spin_lock_irqsave(&part->chctl_lock, irq_flags); + part->chctl.flags[msg->ch_number] |= + XPC_CHCTL_OPENREPLY; + spin_unlock_irqrestore(&part->chctl_lock, irq_flags); + + xpc_wakeup_channel_mgr(part); + break; + } + case XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV: + spin_lock_irqsave(&part_uv->flags_lock, irq_flags); + part_uv->flags |= XPC_P_ENGAGED_UV; + spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); + break; + + case XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV: + spin_lock_irqsave(&part_uv->flags_lock, irq_flags); + part_uv->flags &= ~XPC_P_ENGAGED_UV; + spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); + break; + + default: + dev_err(xpc_part, "received unknown activate_mq msg " + "type=%d from partition=%d\n", msg_hdr->type, + partid); + } + + if (msg_hdr->rp_ts_jiffies != part->remote_rp_ts_jiffies && + part->remote_rp_ts_jiffies != 0) { + /* + * ??? Does what we do here need to be sensitive to + * ??? act_state or remote_act_state? + */ + spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, + irq_flags); + if (part_uv->act_state_req == 0) + xpc_activate_IRQ_rcvd++; + part_uv->act_state_req = XPC_P_ASR_REACTIVATE_UV; + spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, + irq_flags); + wakeup_hb_checker++; + } + + gru_free_message(xpc_activate_mq_uv, msg_hdr); + } + + if (wakeup_hb_checker) + wake_up_interruptible(&xpc_activate_IRQ_wq); + + return IRQ_HANDLED; +} + +static enum xp_retval +xpc_send_activate_IRQ_uv(struct xpc_partition *part, void *msg, size_t msg_size, + int msg_type) +{ + struct xpc_activate_mq_msghdr_uv *msg_hdr = msg; + + DBUG_ON(msg_size > XPC_ACTIVATE_MSG_SIZE_UV); + + msg_hdr->type = msg_type; + msg_hdr->partid = XPC_PARTID(part); + msg_hdr->act_state = part->act_state; + msg_hdr->rp_ts_jiffies = xpc_rsvd_page->ts_jiffies; + + /* ??? Is holding a spin_lock (ch->lock) during this call a bad idea? */ + return xpc_send_gru_msg(part->sn.uv.remote_activate_mq_gpa, msg, + msg_size); +} + +static void +xpc_send_activate_IRQ_part_uv(struct xpc_partition *part, void *msg, + size_t msg_size, int msg_type) +{ + enum xp_retval ret; + + ret = xpc_send_activate_IRQ_uv(part, msg, msg_size, msg_type); + if (unlikely(ret != xpSuccess)) + XPC_DEACTIVATE_PARTITION(part, ret); +} + +static void +xpc_send_activate_IRQ_ch_uv(struct xpc_channel *ch, unsigned long *irq_flags, + void *msg, size_t msg_size, int msg_type) +{ + struct xpc_partition *part = &xpc_partitions[ch->number]; + enum xp_retval ret; + + ret = xpc_send_activate_IRQ_uv(part, msg, msg_size, msg_type); + if (unlikely(ret != xpSuccess)) { + if (irq_flags != NULL) + spin_unlock_irqrestore(&ch->lock, *irq_flags); + + XPC_DEACTIVATE_PARTITION(part, ret); + + if (irq_flags != NULL) + spin_lock_irqsave(&ch->lock, *irq_flags); + } +} + +static void +xpc_send_local_activate_IRQ_uv(struct xpc_partition *part, int act_state_req) +{ + unsigned long irq_flags; + struct xpc_partition_uv *part_uv = &part->sn.uv; + /* * !!! Make our side think that the remote parition sent an activate - * !!! message our way. Also do what the activate IRQ handler would + * !!! message our way by doing what the activate IRQ handler would * !!! do had one really been sent. */ + + spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); + if (part_uv->act_state_req == 0) + xpc_activate_IRQ_rcvd++; + part_uv->act_state_req = act_state_req; + spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); + + wake_up_interruptible(&xpc_activate_IRQ_wq); } static enum xp_retval -xpc_rsvd_page_init_uv(struct xpc_rsvd_page *rp) +xpc_get_partition_rsvd_page_pa_uv(void *buf, u64 *cookie, unsigned long *rp_pa, + size_t *len) { - /* !!! need to have established xpc_activate_mq earlier */ - rp->sn.activate_mq_gpa = uv_gpa(xpc_activate_mq); - return xpSuccess; + /* !!! call the UV version of sn_partition_reserved_page_pa() */ + return xpUnsupported; +} + +static int +xpc_setup_rsvd_page_sn_uv(struct xpc_rsvd_page *rp) +{ + rp->sn.activate_mq_gpa = uv_gpa(xpc_activate_mq_uv); + return 0; +} + +static void +xpc_send_heartbeat_uv(int msg_type) +{ + short partid; + struct xpc_partition *part; + struct xpc_activate_mq_msg_heartbeat_req_uv msg; + + /* + * !!! On uv we're broadcasting a heartbeat message every 5 seconds. + * !!! Whereas on sn2 we're bte_copy'ng the heartbeat info every 20 + * !!! seconds. This is an increase in numalink traffic. + * ??? Is this good? + */ + + msg.heartbeat = atomic64_inc_return(&xpc_heartbeat_uv); + + partid = find_first_bit(xpc_heartbeating_to_mask_uv, + XP_MAX_NPARTITIONS_UV); + + while (partid < XP_MAX_NPARTITIONS_UV) { + part = &xpc_partitions[partid]; + + xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), + msg_type); + + partid = find_next_bit(xpc_heartbeating_to_mask_uv, + XP_MAX_NPARTITIONS_UV, partid + 1); + } } static void xpc_increment_heartbeat_uv(void) { - /* !!! send heartbeat msg to xpc_heartbeating_to_mask partids */ + xpc_send_heartbeat_uv(XPC_ACTIVATE_MQ_MSG_INC_HEARTBEAT_UV); +} + +static void +xpc_offline_heartbeat_uv(void) +{ + xpc_send_heartbeat_uv(XPC_ACTIVATE_MQ_MSG_OFFLINE_HEARTBEAT_UV); +} + +static void +xpc_online_heartbeat_uv(void) +{ + xpc_send_heartbeat_uv(XPC_ACTIVATE_MQ_MSG_ONLINE_HEARTBEAT_UV); } static void xpc_heartbeat_init_uv(void) { + atomic64_set(&xpc_heartbeat_uv, 0); bitmap_zero(xpc_heartbeating_to_mask_uv, XP_MAX_NPARTITIONS_UV); xpc_heartbeating_to_mask = &xpc_heartbeating_to_mask_uv[0]; } @@ -56,48 +543,94 @@ xpc_heartbeat_init_uv(void) static void xpc_heartbeat_exit_uv(void) { - /* !!! send heartbeat_offline msg to xpc_heartbeating_to_mask partids */ + xpc_send_heartbeat_uv(XPC_ACTIVATE_MQ_MSG_OFFLINE_HEARTBEAT_UV); +} + +static enum xp_retval +xpc_get_remote_heartbeat_uv(struct xpc_partition *part) +{ + struct xpc_partition_uv *part_uv = &part->sn.uv; + enum xp_retval ret = xpNoHeartbeat; + + if (part_uv->remote_act_state != XPC_P_AS_INACTIVE && + part_uv->remote_act_state != XPC_P_AS_DEACTIVATING) { + + if (part_uv->heartbeat != part->last_heartbeat || + (part_uv->flags & XPC_P_HEARTBEAT_OFFLINE_UV)) { + + part->last_heartbeat = part_uv->heartbeat; + ret = xpSuccess; + } + } + return ret; } static void xpc_request_partition_activation_uv(struct xpc_rsvd_page *remote_rp, - unsigned long remote_rp_pa, int nasid) + unsigned long remote_rp_gpa, int nasid) { short partid = remote_rp->SAL_partid; struct xpc_partition *part = &xpc_partitions[partid]; + struct xpc_activate_mq_msg_activate_req_uv msg; -/* - * !!! Setup part structure with the bits of info we can glean from the rp: - * !!! part->remote_rp_pa = remote_rp_pa; - * !!! part->sn.uv.activate_mq_gpa = remote_rp->sn.activate_mq_gpa; - */ + part->remote_rp_pa = remote_rp_gpa; /* !!! _pa here is really _gpa */ + part->remote_rp_ts_jiffies = remote_rp->ts_jiffies; + part->sn.uv.remote_activate_mq_gpa = remote_rp->sn.activate_mq_gpa; + + /* + * ??? Is it a good idea to make this conditional on what is + * ??? potentially stale state information? + */ + if (part->sn.uv.remote_act_state == XPC_P_AS_INACTIVE) { + msg.rp_gpa = uv_gpa(xpc_rsvd_page); + msg.activate_mq_gpa = xpc_rsvd_page->sn.activate_mq_gpa; + xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), + XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV); + } - xpc_send_local_activate_IRQ_uv(part); + if (part->act_state == XPC_P_AS_INACTIVE) + xpc_send_local_activate_IRQ_uv(part, XPC_P_ASR_ACTIVATE_UV); } static void xpc_request_partition_reactivation_uv(struct xpc_partition *part) { - xpc_send_local_activate_IRQ_uv(part); + xpc_send_local_activate_IRQ_uv(part, XPC_P_ASR_ACTIVATE_UV); +} + +static void +xpc_request_partition_deactivation_uv(struct xpc_partition *part) +{ + struct xpc_activate_mq_msg_deactivate_req_uv msg; + + /* + * ??? Is it a good idea to make this conditional on what is + * ??? potentially stale state information? + */ + if (part->sn.uv.remote_act_state != XPC_P_AS_DEACTIVATING && + part->sn.uv.remote_act_state != XPC_P_AS_INACTIVE) { + + msg.reason = part->reason; + xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), + XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV); + } } /* - * Setup the infrastructure necessary to support XPartition Communication - * between the specified remote partition and the local one. + * Setup the channel structures that are uv specific. */ static enum xp_retval -xpc_setup_infrastructure_uv(struct xpc_partition *part) +xpc_setup_ch_structures_sn_uv(struct xpc_partition *part) { /* !!! this function needs fleshing out */ return xpUnsupported; } /* - * Teardown the infrastructure necessary to support XPartition Communication - * between the specified remote partition and the local one. + * Teardown the channel structures that are uv specific. */ static void -xpc_teardown_infrastructure_uv(struct xpc_partition *part) +xpc_teardown_ch_structures_sn_uv(struct xpc_partition *part) { /* !!! this function needs fleshing out */ return; @@ -106,15 +639,163 @@ xpc_teardown_infrastructure_uv(struct xpc_partition *part) static enum xp_retval xpc_make_first_contact_uv(struct xpc_partition *part) { - /* !!! this function needs fleshing out */ - return xpUnsupported; + struct xpc_activate_mq_msg_uv msg; + + /* + * We send a sync msg to get the remote partition's remote_act_state + * updated to our current act_state which at this point should + * be XPC_P_AS_ACTIVATING. + */ + xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), + XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV); + + while (part->sn.uv.remote_act_state != XPC_P_AS_ACTIVATING) { + + dev_dbg(xpc_part, "waiting to make first contact with " + "partition %d\n", XPC_PARTID(part)); + + /* wait a 1/4 of a second or so */ + (void)msleep_interruptible(250); + + if (part->act_state == XPC_P_AS_DEACTIVATING) + return part->reason; + } + + return xpSuccess; } static u64 xpc_get_chctl_all_flags_uv(struct xpc_partition *part) { + unsigned long irq_flags; + union xpc_channel_ctl_flags chctl; + + spin_lock_irqsave(&part->chctl_lock, irq_flags); + chctl = part->chctl; + if (chctl.all_flags != 0) + part->chctl.all_flags = 0; + + spin_unlock_irqrestore(&part->chctl_lock, irq_flags); + return chctl.all_flags; +} + +static enum xp_retval +xpc_setup_msg_structures_uv(struct xpc_channel *ch) +{ + /* !!! this function needs fleshing out */ + return xpUnsupported; +} + +static void +xpc_teardown_msg_structures_uv(struct xpc_channel *ch) +{ + struct xpc_channel_uv *ch_uv = &ch->sn.uv; + + ch_uv->remote_notify_mq_gpa = 0; + /* !!! this function needs fleshing out */ - return 0UL; +} + +static void +xpc_send_chctl_closerequest_uv(struct xpc_channel *ch, unsigned long *irq_flags) +{ + struct xpc_activate_mq_msg_chctl_closerequest_uv msg; + + msg.ch_number = ch->number; + msg.reason = ch->reason; + xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg), + XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV); +} + +static void +xpc_send_chctl_closereply_uv(struct xpc_channel *ch, unsigned long *irq_flags) +{ + struct xpc_activate_mq_msg_chctl_closereply_uv msg; + + msg.ch_number = ch->number; + xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg), + XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV); +} + +static void +xpc_send_chctl_openrequest_uv(struct xpc_channel *ch, unsigned long *irq_flags) +{ + struct xpc_activate_mq_msg_chctl_openrequest_uv msg; + + msg.ch_number = ch->number; + msg.msg_size = ch->msg_size; + msg.local_nentries = ch->local_nentries; + xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg), + XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV); +} + +static void +xpc_send_chctl_openreply_uv(struct xpc_channel *ch, unsigned long *irq_flags) +{ + struct xpc_activate_mq_msg_chctl_openreply_uv msg; + + msg.ch_number = ch->number; + msg.local_nentries = ch->local_nentries; + msg.remote_nentries = ch->remote_nentries; + msg.local_notify_mq_gpa = uv_gpa(xpc_notify_mq_uv); + xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg), + XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV); +} + +static void +xpc_save_remote_msgqueue_pa_uv(struct xpc_channel *ch, + unsigned long msgqueue_pa) +{ + ch->sn.uv.remote_notify_mq_gpa = msgqueue_pa; +} + +static void +xpc_indicate_partition_engaged_uv(struct xpc_partition *part) +{ + struct xpc_activate_mq_msg_uv msg; + + xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), + XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV); +} + +static void +xpc_indicate_partition_disengaged_uv(struct xpc_partition *part) +{ + struct xpc_activate_mq_msg_uv msg; + + xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), + XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV); +} + +static void +xpc_assume_partition_disengaged_uv(short partid) +{ + struct xpc_partition_uv *part_uv = &xpc_partitions[partid].sn.uv; + unsigned long irq_flags; + + spin_lock_irqsave(&part_uv->flags_lock, irq_flags); + part_uv->flags &= ~XPC_P_ENGAGED_UV; + spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); +} + +static int +xpc_partition_engaged_uv(short partid) +{ + return (xpc_partitions[partid].sn.uv.flags & XPC_P_ENGAGED_UV) != 0; +} + +static int +xpc_any_partition_engaged_uv(void) +{ + struct xpc_partition_uv *part_uv; + short partid; + + for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) { + part_uv = &xpc_partitions[partid].sn.uv; + if ((part_uv->flags & XPC_P_ENGAGED_UV) != 0) + return 1; + } + return 0; } static struct xpc_msg * @@ -124,24 +805,64 @@ xpc_get_deliverable_msg_uv(struct xpc_channel *ch) return NULL; } -void +int xpc_init_uv(void) { - xpc_rsvd_page_init = xpc_rsvd_page_init_uv; + xpc_setup_partitions_sn = xpc_setup_partitions_sn_uv; + xpc_process_activate_IRQ_rcvd = xpc_process_activate_IRQ_rcvd_uv; + xpc_get_partition_rsvd_page_pa = xpc_get_partition_rsvd_page_pa_uv; + xpc_setup_rsvd_page_sn = xpc_setup_rsvd_page_sn_uv; xpc_increment_heartbeat = xpc_increment_heartbeat_uv; + xpc_offline_heartbeat = xpc_offline_heartbeat_uv; + xpc_online_heartbeat = xpc_online_heartbeat_uv; xpc_heartbeat_init = xpc_heartbeat_init_uv; xpc_heartbeat_exit = xpc_heartbeat_exit_uv; + xpc_get_remote_heartbeat = xpc_get_remote_heartbeat_uv; + xpc_request_partition_activation = xpc_request_partition_activation_uv; xpc_request_partition_reactivation = xpc_request_partition_reactivation_uv; - xpc_setup_infrastructure = xpc_setup_infrastructure_uv; - xpc_teardown_infrastructure = xpc_teardown_infrastructure_uv; + xpc_request_partition_deactivation = + xpc_request_partition_deactivation_uv; + + xpc_setup_ch_structures_sn = xpc_setup_ch_structures_sn_uv; + xpc_teardown_ch_structures_sn = xpc_teardown_ch_structures_sn_uv; + xpc_make_first_contact = xpc_make_first_contact_uv; + xpc_get_chctl_all_flags = xpc_get_chctl_all_flags_uv; + xpc_send_chctl_closerequest = xpc_send_chctl_closerequest_uv; + xpc_send_chctl_closereply = xpc_send_chctl_closereply_uv; + xpc_send_chctl_openrequest = xpc_send_chctl_openrequest_uv; + xpc_send_chctl_openreply = xpc_send_chctl_openreply_uv; + + xpc_save_remote_msgqueue_pa = xpc_save_remote_msgqueue_pa_uv; + + xpc_setup_msg_structures = xpc_setup_msg_structures_uv; + xpc_teardown_msg_structures = xpc_teardown_msg_structures_uv; + + xpc_indicate_partition_engaged = xpc_indicate_partition_engaged_uv; + xpc_indicate_partition_disengaged = + xpc_indicate_partition_disengaged_uv; + xpc_assume_partition_disengaged = xpc_assume_partition_disengaged_uv; + xpc_partition_engaged = xpc_partition_engaged_uv; + xpc_any_partition_engaged = xpc_any_partition_engaged_uv; + xpc_get_deliverable_msg = xpc_get_deliverable_msg_uv; + + /* ??? The cpuid argument's value is 0, is that what we want? */ + /* !!! The irq argument's value isn't correct. */ + xpc_activate_mq_uv = xpc_create_gru_mq_uv(XPC_ACTIVATE_MQ_SIZE_UV, 0, 0, + xpc_handle_activate_IRQ_uv); + if (xpc_activate_mq_uv == NULL) + return -ENOMEM; + + return 0; } void xpc_exit_uv(void) { + /* !!! The irq argument's value isn't correct. */ + xpc_destroy_gru_mq_uv(xpc_activate_mq_uv, XPC_ACTIVATE_MQ_SIZE_UV, 0); } -- cgit v1.2.3 From bd3e64c1759e4930315ebf022611468ee9621486 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Tue, 29 Jul 2008 22:34:19 -0700 Subject: sgi-xp: setup the notify GRU message queue Setup the notify GRU message queue that is used for sending user messages on UV systems. Signed-off-by: Dean Nelson Cc: Jack Steiner Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-xp/xp.h | 45 +- drivers/misc/sgi-xp/xp_main.c | 7 +- drivers/misc/sgi-xp/xpc.h | 140 ++++-- drivers/misc/sgi-xp/xpc_channel.c | 63 ++- drivers/misc/sgi-xp/xpc_main.c | 21 +- drivers/misc/sgi-xp/xpc_sn2.c | 178 +++---- drivers/misc/sgi-xp/xpc_uv.c | 951 ++++++++++++++++++++++++++++++-------- drivers/misc/sgi-xp/xpnet.c | 11 +- 8 files changed, 1032 insertions(+), 384 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h index 9ac5758f4d0..859a5281c61 100644 --- a/drivers/misc/sgi-xp/xp.h +++ b/drivers/misc/sgi-xp/xp.h @@ -87,39 +87,18 @@ #endif /* - * The format of an XPC message is as follows: - * - * +-------+--------------------------------+ - * | flags |////////////////////////////////| - * +-------+--------------------------------+ - * | message # | - * +----------------------------------------+ - * | payload (user-defined message) | - * | | - * : - * | | - * +----------------------------------------+ - * - * The size of the payload is defined by the user via xpc_connect(). A user- - * defined message resides in the payload area. - * - * The size of a message entry (within a message queue) must be a cacheline - * sized multiple in order to facilitate the BTE transfer of messages from one - * message queue to another. A macro, XPC_MSG_SIZE(), is provided for the user + * Define macro, XPC_MSG_SIZE(), is provided for the user * that wants to fit as many msg entries as possible in a given memory size * (e.g. a memory page). */ -struct xpc_msg { - u8 flags; /* FOR XPC INTERNAL USE ONLY */ - u8 reserved[7]; /* FOR XPC INTERNAL USE ONLY */ - s64 number; /* FOR XPC INTERNAL USE ONLY */ - - u64 payload; /* user defined portion of message */ -}; +#define XPC_MSG_MAX_SIZE 128 +#define XPC_MSG_HDR_MAX_SIZE 16 +#define XPC_MSG_PAYLOAD_MAX_SIZE (XPC_MSG_MAX_SIZE - XPC_MSG_HDR_MAX_SIZE) -#define XPC_MSG_PAYLOAD_OFFSET (u64) (&((struct xpc_msg *)0)->payload) #define XPC_MSG_SIZE(_payload_size) \ - L1_CACHE_ALIGN(XPC_MSG_PAYLOAD_OFFSET + (_payload_size)) + ALIGN(XPC_MSG_HDR_MAX_SIZE + (_payload_size), \ + is_uv() ? 64 : 128) + /* * Define the return values and values passed to user's callout functions. @@ -210,7 +189,10 @@ enum xp_retval { xpGruCopyError, /* 58: gru_copy_gru() returned error */ xpGruSendMqError, /* 59: gru send message queue related error */ - xpUnknownReason /* 60: unknown reason - must be last in enum */ + xpBadChannelNumber, /* 60: invalid channel number */ + xpBadMsgType, /* 60: invalid message type */ + + xpUnknownReason /* 61: unknown reason - must be last in enum */ }; /* @@ -261,6 +243,9 @@ typedef void (*xpc_channel_func) (enum xp_retval reason, short partid, * calling xpc_received(). * * All other reason codes indicate failure. + * + * NOTE: The user defined function must be callable by an interrupt handler + * and thus cannot block. */ typedef void (*xpc_notify_func) (enum xp_retval reason, short partid, int ch_number, void *key); @@ -284,7 +269,7 @@ struct xpc_registration { xpc_channel_func func; /* function to call */ void *key; /* pointer to user's key */ u16 nentries; /* #of msg entries in local msg queue */ - u16 msg_size; /* message queue's message size */ + u16 entry_size; /* message queue's message entry size */ u32 assigned_limit; /* limit on #of assigned kthreads */ u32 idle_limit; /* limit on #of idle kthreads */ } ____cacheline_aligned; diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c index f86ad3af26b..66a1d19e08a 100644 --- a/drivers/misc/sgi-xp/xp_main.c +++ b/drivers/misc/sgi-xp/xp_main.c @@ -154,6 +154,9 @@ xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size, DBUG_ON(func == NULL); DBUG_ON(assigned_limit == 0 || idle_limit > assigned_limit); + if (XPC_MSG_SIZE(payload_size) > XPC_MSG_MAX_SIZE) + return xpPayloadTooBig; + registration = &xpc_registrations[ch_number]; if (mutex_lock_interruptible(®istration->mutex) != 0) @@ -166,7 +169,7 @@ xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size, } /* register the channel for connection */ - registration->msg_size = XPC_MSG_SIZE(payload_size); + registration->entry_size = XPC_MSG_SIZE(payload_size); registration->nentries = nentries; registration->assigned_limit = assigned_limit; registration->idle_limit = idle_limit; @@ -220,7 +223,7 @@ xpc_disconnect(int ch_number) registration->func = NULL; registration->key = NULL; registration->nentries = 0; - registration->msg_size = 0; + registration->entry_size = 0; registration->assigned_limit = 0; registration->idle_limit = 0; diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h index 4c26181deff..619208d6186 100644 --- a/drivers/misc/sgi-xp/xpc.h +++ b/drivers/misc/sgi-xp/xpc.h @@ -181,8 +181,8 @@ struct xpc_vars_part_sn2 { xpc_nasid_mask_nlongs)) /* - * The activate_mq is used to send/receive messages that affect XPC's heartbeat, - * partition active state, and channel state. This is UV only. + * The activate_mq is used to send/receive GRU messages that affect XPC's + * heartbeat, partition active state, and channel state. This is UV only. */ struct xpc_activate_mq_msghdr_uv { short partid; /* sender's partid */ @@ -209,45 +209,45 @@ struct xpc_activate_mq_msghdr_uv { #define XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV 11 struct xpc_activate_mq_msg_uv { - struct xpc_activate_mq_msghdr_uv header; + struct xpc_activate_mq_msghdr_uv hdr; }; struct xpc_activate_mq_msg_heartbeat_req_uv { - struct xpc_activate_mq_msghdr_uv header; + struct xpc_activate_mq_msghdr_uv hdr; u64 heartbeat; }; struct xpc_activate_mq_msg_activate_req_uv { - struct xpc_activate_mq_msghdr_uv header; + struct xpc_activate_mq_msghdr_uv hdr; unsigned long rp_gpa; unsigned long activate_mq_gpa; }; struct xpc_activate_mq_msg_deactivate_req_uv { - struct xpc_activate_mq_msghdr_uv header; + struct xpc_activate_mq_msghdr_uv hdr; enum xp_retval reason; }; struct xpc_activate_mq_msg_chctl_closerequest_uv { - struct xpc_activate_mq_msghdr_uv header; + struct xpc_activate_mq_msghdr_uv hdr; short ch_number; enum xp_retval reason; }; struct xpc_activate_mq_msg_chctl_closereply_uv { - struct xpc_activate_mq_msghdr_uv header; + struct xpc_activate_mq_msghdr_uv hdr; short ch_number; }; struct xpc_activate_mq_msg_chctl_openrequest_uv { - struct xpc_activate_mq_msghdr_uv header; + struct xpc_activate_mq_msghdr_uv hdr; short ch_number; - short msg_size; /* size of notify_mq's messages */ + short entry_size; /* size of notify_mq's GRU messages */ short local_nentries; /* ??? Is this needed? What is? */ }; struct xpc_activate_mq_msg_chctl_openreply_uv { - struct xpc_activate_mq_msghdr_uv header; + struct xpc_activate_mq_msghdr_uv hdr; short ch_number; short remote_nentries; /* ??? Is this needed? What is? */ short local_nentries; /* ??? Is this needed? What is? */ @@ -284,7 +284,7 @@ struct xpc_gp_sn2 { */ struct xpc_openclose_args { u16 reason; /* reason why channel is closing */ - u16 msg_size; /* sizeof each message entry */ + u16 entry_size; /* sizeof each message entry */ u16 remote_nentries; /* #of message entries in remote msg queue */ u16 local_nentries; /* #of message entries in local msg queue */ unsigned long local_msgqueue_pa; /* phys addr of local message queue */ @@ -294,22 +294,79 @@ struct xpc_openclose_args { L1_CACHE_ALIGN(sizeof(struct xpc_openclose_args) * \ XPC_MAX_NCHANNELS) -/* struct xpc_msg flags */ -#define XPC_M_DONE 0x01 /* msg has been received/consumed */ -#define XPC_M_READY 0x02 /* msg is ready to be sent */ -#define XPC_M_INTERRUPT 0x04 /* send interrupt when msg consumed */ +/* + * Structures to define a fifo singly-linked list. + */ + +struct xpc_fifo_entry_uv { + struct xpc_fifo_entry_uv *next; +}; + +struct xpc_fifo_head_uv { + struct xpc_fifo_entry_uv *first; + struct xpc_fifo_entry_uv *last; + spinlock_t lock; + int n_entries; +}; + +/* + * Define a sn2 styled message. + * + * A user-defined message resides in the payload area. The max size of the + * payload is defined by the user via xpc_connect(). + * + * The size of a message entry (within a message queue) must be a 128-byte + * cacheline sized multiple in order to facilitate the BTE transfer of messages + * from one message queue to another. + */ +struct xpc_msg_sn2 { + u8 flags; /* FOR XPC INTERNAL USE ONLY */ + u8 reserved[7]; /* FOR XPC INTERNAL USE ONLY */ + s64 number; /* FOR XPC INTERNAL USE ONLY */ + + u64 payload; /* user defined portion of message */ +}; + +/* struct xpc_msg_sn2 flags */ + +#define XPC_M_SN2_DONE 0x01 /* msg has been received/consumed */ +#define XPC_M_SN2_READY 0x02 /* msg is ready to be sent */ +#define XPC_M_SN2_INTERRUPT 0x04 /* send interrupt when msg consumed */ + +/* + * The format of a uv XPC notify_mq GRU message is as follows: + * + * A user-defined message resides in the payload area. The max size of the + * payload is defined by the user via xpc_connect(). + * + * The size of a message (payload and header) sent via the GRU must be either 1 + * or 2 GRU_CACHE_LINE_BYTES in length. + */ -#define XPC_MSG_ADDRESS(_payload) \ - ((struct xpc_msg *)((u8 *)(_payload) - XPC_MSG_PAYLOAD_OFFSET)) +struct xpc_notify_mq_msghdr_uv { + union { + unsigned int gru_msg_hdr; /* FOR GRU INTERNAL USE ONLY */ + struct xpc_fifo_entry_uv next; /* FOR XPC INTERNAL USE ONLY */ + } u; + short partid; /* FOR XPC INTERNAL USE ONLY */ + u8 ch_number; /* FOR XPC INTERNAL USE ONLY */ + u8 size; /* FOR XPC INTERNAL USE ONLY */ + unsigned int msg_slot_number; /* FOR XPC INTERNAL USE ONLY */ +}; + +struct xpc_notify_mq_msg_uv { + struct xpc_notify_mq_msghdr_uv hdr; + unsigned long payload; +}; /* - * Defines notify entry. + * Define sn2's notify entry. * * This is used to notify a message's sender that their message was received * and consumed by the intended recipient. */ -struct xpc_notify { +struct xpc_notify_sn2 { u8 type; /* type of notification */ /* the following two fields are only used if type == XPC_N_CALL */ @@ -317,9 +374,20 @@ struct xpc_notify { void *key; /* pointer to user's key */ }; -/* struct xpc_notify type of notification */ +/* struct xpc_notify_sn2 type of notification */ -#define XPC_N_CALL 0x01 /* notify function provided by user */ +#define XPC_N_CALL 0x01 /* notify function provided by user */ + +/* + * Define uv's version of the notify entry. It additionally is used to allocate + * a msg slot on the remote partition into which is copied a sent message. + */ +struct xpc_send_msg_slot_uv { + struct xpc_fifo_entry_uv next; + unsigned int msg_slot_number; + xpc_notify_func func; /* user's notify function */ + void *key; /* pointer to user's key */ +}; /* * Define the structure that manages all the stuff required by a channel. In @@ -409,14 +477,14 @@ struct xpc_channel_sn2 { /* opening or closing of channel */ void *local_msgqueue_base; /* base address of kmalloc'd space */ - struct xpc_msg *local_msgqueue; /* local message queue */ + struct xpc_msg_sn2 *local_msgqueue; /* local message queue */ void *remote_msgqueue_base; /* base address of kmalloc'd space */ - struct xpc_msg *remote_msgqueue; /* cached copy of remote partition's */ - /* local message queue */ + struct xpc_msg_sn2 *remote_msgqueue; /* cached copy of remote */ + /* partition's local message queue */ unsigned long remote_msgqueue_pa; /* phys addr of remote partition's */ /* local message queue */ - struct xpc_notify *notify_queue; /* notify queue for messages sent */ + struct xpc_notify_sn2 *notify_queue;/* notify queue for messages sent */ /* various flavors of local and remote Get/Put values */ @@ -432,6 +500,12 @@ struct xpc_channel_sn2 { struct xpc_channel_uv { unsigned long remote_notify_mq_gpa; /* gru phys address of remote */ /* partition's notify mq */ + + struct xpc_send_msg_slot_uv *send_msg_slots; + struct xpc_notify_mq_msg_uv *recv_msg_slots; + + struct xpc_fifo_head_uv msg_slot_free_list; + struct xpc_fifo_head_uv recv_msg_list; /* deliverable payloads */ }; struct xpc_channel { @@ -444,7 +518,7 @@ struct xpc_channel { u16 number; /* channel # */ - u16 msg_size; /* sizeof each msg entry */ + u16 entry_size; /* sizeof each msg entry */ u16 local_nentries; /* #of msg entries in local msg queue */ u16 remote_nentries; /* #of msg entries in remote msg queue */ @@ -733,8 +807,8 @@ extern enum xp_retval (*xpc_setup_msg_structures) (struct xpc_channel *); extern void (*xpc_teardown_msg_structures) (struct xpc_channel *); extern void (*xpc_notify_senders_of_disconnect) (struct xpc_channel *); extern void (*xpc_process_msg_chctl_flags) (struct xpc_partition *, int); -extern int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *); -extern struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *); +extern int (*xpc_n_of_deliverable_payloads) (struct xpc_channel *); +extern void *(*xpc_get_deliverable_payload) (struct xpc_channel *); extern void (*xpc_request_partition_activation) (struct xpc_rsvd_page *, unsigned long, int); extern void (*xpc_request_partition_reactivation) (struct xpc_partition *); @@ -762,9 +836,9 @@ extern void (*xpc_send_chctl_openreply) (struct xpc_channel *, unsigned long *); extern void (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *, unsigned long); -extern enum xp_retval (*xpc_send_msg) (struct xpc_channel *, u32, void *, u16, - u8, xpc_notify_func, void *); -extern void (*xpc_received_msg) (struct xpc_channel *, struct xpc_msg *); +extern enum xp_retval (*xpc_send_payload) (struct xpc_channel *, u32, void *, + u16, u8, xpc_notify_func, void *); +extern void (*xpc_received_payload) (struct xpc_channel *, void *); /* found in xpc_sn2.c */ extern int xpc_init_sn2(void); @@ -805,7 +879,7 @@ extern enum xp_retval xpc_initiate_send_notify(short, int, u32, void *, u16, extern void xpc_initiate_received(short, int, void *); extern void xpc_process_sent_chctl_flags(struct xpc_partition *); extern void xpc_connected_callout(struct xpc_channel *); -extern void xpc_deliver_msg(struct xpc_channel *); +extern void xpc_deliver_payload(struct xpc_channel *); extern void xpc_disconnect_channel(const int, struct xpc_channel *, enum xp_retval, unsigned long *); extern void xpc_disconnect_callout(struct xpc_channel *, enum xp_retval); diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index 73df9fb5ee6..9cd2ebe2a3b 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -139,7 +139,7 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) ch->func = NULL; ch->key = NULL; - ch->msg_size = 0; + ch->entry_size = 0; ch->local_nentries = 0; ch->remote_nentries = 0; ch->kthreads_assigned_limit = 0; @@ -315,9 +315,9 @@ again: if (chctl_flags & XPC_CHCTL_OPENREQUEST) { - dev_dbg(xpc_chan, "XPC_CHCTL_OPENREQUEST (msg_size=%d, " + dev_dbg(xpc_chan, "XPC_CHCTL_OPENREQUEST (entry_size=%d, " "local_nentries=%d) received from partid=%d, " - "channel=%d\n", args->msg_size, args->local_nentries, + "channel=%d\n", args->entry_size, args->local_nentries, ch->partid, ch->number); if (part->act_state == XPC_P_AS_DEACTIVATING || @@ -338,10 +338,10 @@ again: /* * The meaningful OPENREQUEST connection state fields are: - * msg_size = size of channel's messages in bytes + * entry_size = size of channel's messages in bytes * local_nentries = remote partition's local_nentries */ - if (args->msg_size == 0 || args->local_nentries == 0) { + if (args->entry_size == 0 || args->local_nentries == 0) { /* assume OPENREQUEST was delayed by mistake */ spin_unlock_irqrestore(&ch->lock, irq_flags); return; @@ -351,14 +351,14 @@ again: ch->remote_nentries = args->local_nentries; if (ch->flags & XPC_C_OPENREQUEST) { - if (args->msg_size != ch->msg_size) { + if (args->entry_size != ch->entry_size) { XPC_DISCONNECT_CHANNEL(ch, xpUnequalMsgSizes, &irq_flags); spin_unlock_irqrestore(&ch->lock, irq_flags); return; } } else { - ch->msg_size = args->msg_size; + ch->entry_size = args->entry_size; XPC_SET_REASON(ch, 0, 0); ch->flags &= ~XPC_C_DISCONNECTED; @@ -473,7 +473,7 @@ xpc_connect_channel(struct xpc_channel *ch) ch->local_nentries = registration->nentries; if (ch->flags & XPC_C_ROPENREQUEST) { - if (registration->msg_size != ch->msg_size) { + if (registration->entry_size != ch->entry_size) { /* the local and remote sides aren't the same */ /* @@ -492,7 +492,7 @@ xpc_connect_channel(struct xpc_channel *ch) return xpUnequalMsgSizes; } } else { - ch->msg_size = registration->msg_size; + ch->entry_size = registration->entry_size; XPC_SET_REASON(ch, 0, 0); ch->flags &= ~XPC_C_DISCONNECTED; @@ -859,8 +859,8 @@ xpc_initiate_send(short partid, int ch_number, u32 flags, void *payload, DBUG_ON(payload == NULL); if (xpc_part_ref(part)) { - ret = xpc_send_msg(&part->channels[ch_number], flags, payload, - payload_size, 0, NULL, NULL); + ret = xpc_send_payload(&part->channels[ch_number], flags, + payload, payload_size, 0, NULL, NULL); xpc_part_deref(part); } @@ -911,23 +911,24 @@ xpc_initiate_send_notify(short partid, int ch_number, u32 flags, void *payload, DBUG_ON(func == NULL); if (xpc_part_ref(part)) { - ret = xpc_send_msg(&part->channels[ch_number], flags, payload, - payload_size, XPC_N_CALL, func, key); + ret = xpc_send_payload(&part->channels[ch_number], flags, + payload, payload_size, XPC_N_CALL, func, + key); xpc_part_deref(part); } return ret; } /* - * Deliver a message to its intended recipient. + * Deliver a message's payload to its intended recipient. */ void -xpc_deliver_msg(struct xpc_channel *ch) +xpc_deliver_payload(struct xpc_channel *ch) { - struct xpc_msg *msg; + void *payload; - msg = xpc_get_deliverable_msg(ch); - if (msg != NULL) { + payload = xpc_get_deliverable_payload(ch); + if (payload != NULL) { /* * This ref is taken to protect the payload itself from being @@ -939,18 +940,16 @@ xpc_deliver_msg(struct xpc_channel *ch) atomic_inc(&ch->kthreads_active); if (ch->func != NULL) { - dev_dbg(xpc_chan, "ch->func() called, msg=0x%p, " - "msg_number=%ld, partid=%d, channel=%d\n", - msg, (signed long)msg->number, ch->partid, + dev_dbg(xpc_chan, "ch->func() called, payload=0x%p " + "partid=%d channel=%d\n", payload, ch->partid, ch->number); /* deliver the message to its intended recipient */ - ch->func(xpMsgReceived, ch->partid, ch->number, - &msg->payload, ch->key); + ch->func(xpMsgReceived, ch->partid, ch->number, payload, + ch->key); - dev_dbg(xpc_chan, "ch->func() returned, msg=0x%p, " - "msg_number=%ld, partid=%d, channel=%d\n", - msg, (signed long)msg->number, ch->partid, + dev_dbg(xpc_chan, "ch->func() returned, payload=0x%p " + "partid=%d channel=%d\n", payload, ch->partid, ch->number); } @@ -959,14 +958,11 @@ xpc_deliver_msg(struct xpc_channel *ch) } /* - * Acknowledge receipt of a delivered message. - * - * If a message has XPC_M_INTERRUPT set, send an interrupt to the partition - * that sent the message. + * Acknowledge receipt of a delivered message's payload. * * This function, although called by users, does not call xpc_part_ref() to * ensure that the partition infrastructure is in place. It relies on the - * fact that we called xpc_msgqueue_ref() in xpc_deliver_msg(). + * fact that we called xpc_msgqueue_ref() in xpc_deliver_payload(). * * Arguments: * @@ -980,14 +976,13 @@ xpc_initiate_received(short partid, int ch_number, void *payload) { struct xpc_partition *part = &xpc_partitions[partid]; struct xpc_channel *ch; - struct xpc_msg *msg = XPC_MSG_ADDRESS(payload); DBUG_ON(partid < 0 || partid >= xp_max_npartitions); DBUG_ON(ch_number < 0 || ch_number >= part->nchannels); ch = &part->channels[ch_number]; - xpc_received_msg(ch, msg); + xpc_received_payload(ch, payload); - /* the call to xpc_msgqueue_ref() was done by xpc_deliver_msg() */ + /* the call to xpc_msgqueue_ref() was done by xpc_deliver_payload() */ xpc_msgqueue_deref(ch); } diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index 13ec4792899..46325fc8481 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -188,8 +188,8 @@ u64 (*xpc_get_chctl_all_flags) (struct xpc_partition *part); enum xp_retval (*xpc_setup_msg_structures) (struct xpc_channel *ch); void (*xpc_teardown_msg_structures) (struct xpc_channel *ch); void (*xpc_process_msg_chctl_flags) (struct xpc_partition *part, int ch_number); -int (*xpc_n_of_deliverable_msgs) (struct xpc_channel *ch); -struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *ch); +int (*xpc_n_of_deliverable_payloads) (struct xpc_channel *ch); +void *(*xpc_get_deliverable_payload) (struct xpc_channel *ch); void (*xpc_request_partition_activation) (struct xpc_rsvd_page *remote_rp, unsigned long remote_rp_pa, @@ -220,10 +220,11 @@ void (*xpc_send_chctl_openreply) (struct xpc_channel *ch, void (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *ch, unsigned long msgqueue_pa); -enum xp_retval (*xpc_send_msg) (struct xpc_channel *ch, u32 flags, - void *payload, u16 payload_size, u8 notify_type, - xpc_notify_func func, void *key); -void (*xpc_received_msg) (struct xpc_channel *ch, struct xpc_msg *msg); +enum xp_retval (*xpc_send_payload) (struct xpc_channel *ch, u32 flags, + void *payload, u16 payload_size, + u8 notify_type, xpc_notify_func func, + void *key); +void (*xpc_received_payload) (struct xpc_channel *ch, void *payload); /* * Timer function to enforce the timelimit on the partition disengage. @@ -714,9 +715,9 @@ xpc_kthread_waitmsgs(struct xpc_partition *part, struct xpc_channel *ch) do { /* deliver messages to their intended recipients */ - while (xpc_n_of_deliverable_msgs(ch) > 0 && + while (xpc_n_of_deliverable_payloads(ch) > 0 && !(ch->flags & XPC_C_DISCONNECTING)) { - xpc_deliver_msg(ch); + xpc_deliver_payload(ch); } if (atomic_inc_return(&ch->kthreads_idle) > @@ -730,7 +731,7 @@ xpc_kthread_waitmsgs(struct xpc_partition *part, struct xpc_channel *ch) "wait_event_interruptible_exclusive()\n"); (void)wait_event_interruptible_exclusive(ch->idle_wq, - (xpc_n_of_deliverable_msgs(ch) > 0 || + (xpc_n_of_deliverable_payloads(ch) > 0 || (ch->flags & XPC_C_DISCONNECTING))); atomic_dec(&ch->kthreads_idle); @@ -775,7 +776,7 @@ xpc_kthread_start(void *args) * additional kthreads to help deliver them. We only * need one less than total #of messages to deliver. */ - n_needed = xpc_n_of_deliverable_msgs(ch) - 1; + n_needed = xpc_n_of_deliverable_payloads(ch) - 1; if (n_needed > 0 && !(ch->flags & XPC_C_DISCONNECTING)) xpc_activate_kthreads(ch, n_needed); diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index 8b4b0653d9e..b4882ccf634 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -408,7 +408,7 @@ xpc_send_chctl_openrequest_sn2(struct xpc_channel *ch, unsigned long *irq_flags) { struct xpc_openclose_args *args = ch->sn.sn2.local_openclose_args; - args->msg_size = ch->msg_size; + args->entry_size = ch->entry_size; args->local_nentries = ch->local_nentries; XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_OPENREQUEST, irq_flags); } @@ -1531,14 +1531,14 @@ xpc_allocate_local_msgqueue_sn2(struct xpc_channel *ch) for (nentries = ch->local_nentries; nentries > 0; nentries--) { - nbytes = nentries * ch->msg_size; + nbytes = nentries * ch->entry_size; ch_sn2->local_msgqueue = xpc_kzalloc_cacheline_aligned(nbytes, GFP_KERNEL, &ch_sn2->local_msgqueue_base); if (ch_sn2->local_msgqueue == NULL) continue; - nbytes = nentries * sizeof(struct xpc_notify); + nbytes = nentries * sizeof(struct xpc_notify_sn2); ch_sn2->notify_queue = kzalloc(nbytes, GFP_KERNEL); if (ch_sn2->notify_queue == NULL) { kfree(ch_sn2->local_msgqueue_base); @@ -1578,7 +1578,7 @@ xpc_allocate_remote_msgqueue_sn2(struct xpc_channel *ch) for (nentries = ch->remote_nentries; nentries > 0; nentries--) { - nbytes = nentries * ch->msg_size; + nbytes = nentries * ch->entry_size; ch_sn2->remote_msgqueue = xpc_kzalloc_cacheline_aligned(nbytes, GFP_KERNEL, &ch_sn2-> remote_msgqueue_base); @@ -1632,9 +1632,6 @@ xpc_setup_msg_structures_sn2(struct xpc_channel *ch) /* * Free up message queues and other stuff that were allocated for the specified * channel. - * - * Note: ch->reason and ch->reason_line are left set for debugging purposes, - * they're cleared when XPC_C_DISCONNECTED is cleared. */ static void xpc_teardown_msg_structures_sn2(struct xpc_channel *ch) @@ -1674,7 +1671,7 @@ xpc_teardown_msg_structures_sn2(struct xpc_channel *ch) static void xpc_notify_senders_sn2(struct xpc_channel *ch, enum xp_retval reason, s64 put) { - struct xpc_notify *notify; + struct xpc_notify_sn2 *notify; u8 notify_type; s64 get = ch->sn.sn2.w_remote_GP.get - 1; @@ -1699,17 +1696,16 @@ xpc_notify_senders_sn2(struct xpc_channel *ch, enum xp_retval reason, s64 put) atomic_dec(&ch->n_to_notify); if (notify->func != NULL) { - dev_dbg(xpc_chan, "notify->func() called, notify=0x%p, " - "msg_number=%ld, partid=%d, channel=%d\n", + dev_dbg(xpc_chan, "notify->func() called, notify=0x%p " + "msg_number=%ld partid=%d channel=%d\n", (void *)notify, get, ch->partid, ch->number); notify->func(reason, ch->partid, ch->number, notify->key); - dev_dbg(xpc_chan, "notify->func() returned, " - "notify=0x%p, msg_number=%ld, partid=%d, " - "channel=%d\n", (void *)notify, get, - ch->partid, ch->number); + dev_dbg(xpc_chan, "notify->func() returned, notify=0x%p" + " msg_number=%ld partid=%d channel=%d\n", + (void *)notify, get, ch->partid, ch->number); } } } @@ -1727,14 +1723,14 @@ static inline void xpc_clear_local_msgqueue_flags_sn2(struct xpc_channel *ch) { struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; - struct xpc_msg *msg; + struct xpc_msg_sn2 *msg; s64 get; get = ch_sn2->w_remote_GP.get; do { - msg = (struct xpc_msg *)((u64)ch_sn2->local_msgqueue + - (get % ch->local_nentries) * - ch->msg_size); + msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->local_msgqueue + + (get % ch->local_nentries) * + ch->entry_size); msg->flags = 0; } while (++get < ch_sn2->remote_GP.get); } @@ -1746,24 +1742,30 @@ static inline void xpc_clear_remote_msgqueue_flags_sn2(struct xpc_channel *ch) { struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; - struct xpc_msg *msg; + struct xpc_msg_sn2 *msg; s64 put; put = ch_sn2->w_remote_GP.put; do { - msg = (struct xpc_msg *)((u64)ch_sn2->remote_msgqueue + - (put % ch->remote_nentries) * - ch->msg_size); + msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue + + (put % ch->remote_nentries) * + ch->entry_size); msg->flags = 0; } while (++put < ch_sn2->remote_GP.put); } +static int +xpc_n_of_deliverable_payloads_sn2(struct xpc_channel *ch) +{ + return ch->sn.sn2.w_remote_GP.put - ch->sn.sn2.w_local_GP.get; +} + static void xpc_process_msg_chctl_flags_sn2(struct xpc_partition *part, int ch_number) { struct xpc_channel *ch = &part->channels[ch_number]; struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; - int nmsgs_sent; + int npayloads_sent; ch_sn2->remote_GP = part->sn.sn2.remote_GPs[ch_number]; @@ -1835,7 +1837,7 @@ xpc_process_msg_chctl_flags_sn2(struct xpc_partition *part, int ch_number) if (ch_sn2->w_remote_GP.put != ch_sn2->remote_GP.put) { /* * Clear msg->flags in previously received messages, so that - * they're ready for xpc_get_deliverable_msg(). + * they're ready for xpc_get_deliverable_payload_sn2(). */ xpc_clear_remote_msgqueue_flags_sn2(ch); @@ -1845,27 +1847,27 @@ xpc_process_msg_chctl_flags_sn2(struct xpc_partition *part, int ch_number) "channel=%d\n", ch_sn2->w_remote_GP.put, ch->partid, ch->number); - nmsgs_sent = ch_sn2->w_remote_GP.put - ch_sn2->w_local_GP.get; - if (nmsgs_sent > 0) { + npayloads_sent = xpc_n_of_deliverable_payloads_sn2(ch); + if (npayloads_sent > 0) { dev_dbg(xpc_chan, "msgs waiting to be copied and " "delivered=%d, partid=%d, channel=%d\n", - nmsgs_sent, ch->partid, ch->number); + npayloads_sent, ch->partid, ch->number); if (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) - xpc_activate_kthreads(ch, nmsgs_sent); + xpc_activate_kthreads(ch, npayloads_sent); } } xpc_msgqueue_deref(ch); } -static struct xpc_msg * +static struct xpc_msg_sn2 * xpc_pull_remote_msg_sn2(struct xpc_channel *ch, s64 get) { struct xpc_partition *part = &xpc_partitions[ch->partid]; struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; unsigned long remote_msg_pa; - struct xpc_msg *msg; + struct xpc_msg_sn2 *msg; u32 msg_index; u32 nmsgs; u64 msg_offset; @@ -1889,13 +1891,13 @@ xpc_pull_remote_msg_sn2(struct xpc_channel *ch, s64 get) nmsgs = ch->remote_nentries - msg_index; } - msg_offset = msg_index * ch->msg_size; - msg = (struct xpc_msg *)((u64)ch_sn2->remote_msgqueue + + msg_offset = msg_index * ch->entry_size; + msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue + msg_offset); remote_msg_pa = ch_sn2->remote_msgqueue_pa + msg_offset; ret = xpc_pull_remote_cachelines_sn2(part, msg, remote_msg_pa, - nmsgs * ch->msg_size); + nmsgs * ch->entry_size); if (ret != xpSuccess) { dev_dbg(xpc_chan, "failed to pull %d msgs starting with" @@ -1915,26 +1917,21 @@ xpc_pull_remote_msg_sn2(struct xpc_channel *ch, s64 get) mutex_unlock(&ch_sn2->msg_to_pull_mutex); /* return the message we were looking for */ - msg_offset = (get % ch->remote_nentries) * ch->msg_size; - msg = (struct xpc_msg *)((u64)ch_sn2->remote_msgqueue + msg_offset); + msg_offset = (get % ch->remote_nentries) * ch->entry_size; + msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue + msg_offset); return msg; } -static int -xpc_n_of_deliverable_msgs_sn2(struct xpc_channel *ch) -{ - return ch->sn.sn2.w_remote_GP.put - ch->sn.sn2.w_local_GP.get; -} - /* - * Get a message to be delivered. + * Get the next deliverable message's payload. */ -static struct xpc_msg * -xpc_get_deliverable_msg_sn2(struct xpc_channel *ch) +static void * +xpc_get_deliverable_payload_sn2(struct xpc_channel *ch) { struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; - struct xpc_msg *msg = NULL; + struct xpc_msg_sn2 *msg; + void *payload = NULL; s64 get; do { @@ -1965,15 +1962,16 @@ xpc_get_deliverable_msg_sn2(struct xpc_channel *ch) msg = xpc_pull_remote_msg_sn2(ch, get); DBUG_ON(msg != NULL && msg->number != get); - DBUG_ON(msg != NULL && (msg->flags & XPC_M_DONE)); - DBUG_ON(msg != NULL && !(msg->flags & XPC_M_READY)); + DBUG_ON(msg != NULL && (msg->flags & XPC_M_SN2_DONE)); + DBUG_ON(msg != NULL && !(msg->flags & XPC_M_SN2_READY)); + payload = &msg->payload; break; } } while (1); - return msg; + return payload; } /* @@ -1985,7 +1983,7 @@ static void xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put) { struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; - struct xpc_msg *msg; + struct xpc_msg_sn2 *msg; s64 put = initial_put + 1; int send_msgrequest = 0; @@ -1995,11 +1993,12 @@ xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put) if (put == ch_sn2->w_local_GP.put) break; - msg = (struct xpc_msg *)((u64)ch_sn2->local_msgqueue + - (put % ch->local_nentries) * - ch->msg_size); + msg = (struct xpc_msg_sn2 *)((u64)ch_sn2-> + local_msgqueue + (put % + ch->local_nentries) * + ch->entry_size); - if (!(msg->flags & XPC_M_READY)) + if (!(msg->flags & XPC_M_SN2_READY)) break; put++; @@ -2026,7 +2025,7 @@ xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put) /* * We need to ensure that the message referenced by - * local_GP->put is not XPC_M_READY or that local_GP->put + * local_GP->put is not XPC_M_SN2_READY or that local_GP->put * equals w_local_GP.put, so we'll go have a look. */ initial_put = put; @@ -2042,10 +2041,10 @@ xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put) */ static enum xp_retval xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags, - struct xpc_msg **address_of_msg) + struct xpc_msg_sn2 **address_of_msg) { struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; - struct xpc_msg *msg; + struct xpc_msg_sn2 *msg; enum xp_retval ret; s64 put; @@ -2097,8 +2096,9 @@ xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags, } /* get the message's address and initialize it */ - msg = (struct xpc_msg *)((u64)ch_sn2->local_msgqueue + - (put % ch->local_nentries) * ch->msg_size); + msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->local_msgqueue + + (put % ch->local_nentries) * + ch->entry_size); DBUG_ON(msg->flags != 0); msg->number = put; @@ -2117,20 +2117,20 @@ xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags, * partition the message is being sent to. */ static enum xp_retval -xpc_send_msg_sn2(struct xpc_channel *ch, u32 flags, void *payload, - u16 payload_size, u8 notify_type, xpc_notify_func func, - void *key) +xpc_send_payload_sn2(struct xpc_channel *ch, u32 flags, void *payload, + u16 payload_size, u8 notify_type, xpc_notify_func func, + void *key) { enum xp_retval ret = xpSuccess; struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; - struct xpc_msg *msg = msg; - struct xpc_notify *notify = notify; + struct xpc_msg_sn2 *msg = msg; + struct xpc_notify_sn2 *notify = notify; s64 msg_number; s64 put; DBUG_ON(notify_type == XPC_N_CALL && func == NULL); - if (XPC_MSG_SIZE(payload_size) > ch->msg_size) + if (XPC_MSG_SIZE(payload_size) > ch->entry_size) return xpPayloadTooBig; xpc_msgqueue_ref(ch); @@ -2155,7 +2155,7 @@ xpc_send_msg_sn2(struct xpc_channel *ch, u32 flags, void *payload, * Tell the remote side to send an ACK interrupt when the * message has been delivered. */ - msg->flags |= XPC_M_INTERRUPT; + msg->flags |= XPC_M_SN2_INTERRUPT; atomic_inc(&ch->n_to_notify); @@ -2185,7 +2185,7 @@ xpc_send_msg_sn2(struct xpc_channel *ch, u32 flags, void *payload, memcpy(&msg->payload, payload, payload_size); - msg->flags |= XPC_M_READY; + msg->flags |= XPC_M_SN2_READY; /* * The preceding store of msg->flags must occur before the following @@ -2208,12 +2208,15 @@ out_1: * Now we actually acknowledge the messages that have been delivered and ack'd * by advancing the cached remote message queue's Get value and if requested * send a chctl msgrequest to the message sender's partition. + * + * If a message has XPC_M_SN2_INTERRUPT set, send an interrupt to the partition + * that sent the message. */ static void xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) { struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; - struct xpc_msg *msg; + struct xpc_msg_sn2 *msg; s64 get = initial_get + 1; int send_msgrequest = 0; @@ -2223,11 +2226,12 @@ xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) if (get == ch_sn2->w_local_GP.get) break; - msg = (struct xpc_msg *)((u64)ch_sn2->remote_msgqueue + - (get % ch->remote_nentries) * - ch->msg_size); + msg = (struct xpc_msg_sn2 *)((u64)ch_sn2-> + remote_msgqueue + (get % + ch->remote_nentries) * + ch->entry_size); - if (!(msg->flags & XPC_M_DONE)) + if (!(msg->flags & XPC_M_SN2_DONE)) break; msg_flags |= msg->flags; @@ -2251,11 +2255,11 @@ xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) dev_dbg(xpc_chan, "local_GP->get changed to %ld, partid=%d, " "channel=%d\n", get, ch->partid, ch->number); - send_msgrequest = (msg_flags & XPC_M_INTERRUPT); + send_msgrequest = (msg_flags & XPC_M_SN2_INTERRUPT); /* * We need to ensure that the message referenced by - * local_GP->get is not XPC_M_DONE or that local_GP->get + * local_GP->get is not XPC_M_SN2_DONE or that local_GP->get * equals w_local_GP.get, so we'll go have a look. */ initial_get = get; @@ -2266,19 +2270,23 @@ xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags) } static void -xpc_received_msg_sn2(struct xpc_channel *ch, struct xpc_msg *msg) +xpc_received_payload_sn2(struct xpc_channel *ch, void *payload) { + struct xpc_msg_sn2 *msg; + s64 msg_number; s64 get; - s64 msg_number = msg->number; + + msg = container_of(payload, struct xpc_msg_sn2, payload); + msg_number = msg->number; dev_dbg(xpc_chan, "msg=0x%p, msg_number=%ld, partid=%d, channel=%d\n", (void *)msg, msg_number, ch->partid, ch->number); - DBUG_ON((((u64)msg - (u64)ch->remote_msgqueue) / ch->msg_size) != + DBUG_ON((((u64)msg - (u64)ch->remote_msgqueue) / ch->entry_size) != msg_number % ch->remote_nentries); - DBUG_ON(msg->flags & XPC_M_DONE); + DBUG_ON(msg->flags & XPC_M_SN2_DONE); - msg->flags |= XPC_M_DONE; + msg->flags |= XPC_M_SN2_DONE; /* * The preceding store of msg->flags must occur before the following @@ -2337,8 +2345,8 @@ xpc_init_sn2(void) xpc_notify_senders_of_disconnect = xpc_notify_senders_of_disconnect_sn2; xpc_process_msg_chctl_flags = xpc_process_msg_chctl_flags_sn2; - xpc_n_of_deliverable_msgs = xpc_n_of_deliverable_msgs_sn2; - xpc_get_deliverable_msg = xpc_get_deliverable_msg_sn2; + xpc_n_of_deliverable_payloads = xpc_n_of_deliverable_payloads_sn2; + xpc_get_deliverable_payload = xpc_get_deliverable_payload_sn2; xpc_indicate_partition_engaged = xpc_indicate_partition_engaged_sn2; xpc_indicate_partition_disengaged = @@ -2347,8 +2355,14 @@ xpc_init_sn2(void) xpc_any_partition_engaged = xpc_any_partition_engaged_sn2; xpc_assume_partition_disengaged = xpc_assume_partition_disengaged_sn2; - xpc_send_msg = xpc_send_msg_sn2; - xpc_received_msg = xpc_received_msg_sn2; + xpc_send_payload = xpc_send_payload_sn2; + xpc_received_payload = xpc_received_payload_sn2; + + if (offsetof(struct xpc_msg_sn2, payload) > XPC_MSG_HDR_MAX_SIZE) { + dev_err(xpc_part, "header portion of struct xpc_msg_sn2 is " + "larger than %d\n", XPC_MSG_HDR_MAX_SIZE); + return -E2BIG; + } buf_size = max(XPC_RP_VARS_SIZE, XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES_SN2); diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index 689cb5c68cc..1ac694c0162 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c @@ -66,8 +66,11 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpuid, unsigned int irq, mq_order = get_order(mq_size); page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE, mq_order); - if (page == NULL) + if (page == NULL) { + dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d " + "bytes of memory on nid=%d for GRU mq\n", mq_size, nid); return NULL; + } mq = page_address(page); ret = gru_create_message_queue(mq, mq_size); @@ -193,202 +196,226 @@ xpc_process_activate_IRQ_rcvd_uv(void) } -static irqreturn_t -xpc_handle_activate_IRQ_uv(int irq, void *dev_id) +static void +xpc_handle_activate_mq_msg_uv(struct xpc_partition *part, + struct xpc_activate_mq_msghdr_uv *msg_hdr, + int *wakeup_hb_checker) { unsigned long irq_flags; - struct xpc_activate_mq_msghdr_uv *msg_hdr; - short partid; - struct xpc_partition *part; - struct xpc_partition_uv *part_uv; + struct xpc_partition_uv *part_uv = &part->sn.uv; struct xpc_openclose_args *args; - int wakeup_hb_checker = 0; - while ((msg_hdr = gru_get_next_message(xpc_activate_mq_uv)) != NULL) { + part_uv->remote_act_state = msg_hdr->act_state; - partid = msg_hdr->partid; - if (partid < 0 || partid >= XP_MAX_NPARTITIONS_UV) { - dev_err(xpc_part, "xpc_handle_activate_IRQ_uv() invalid" - "partid=0x%x passed in message\n", partid); - gru_free_message(xpc_activate_mq_uv, msg_hdr); - continue; - } - part = &xpc_partitions[partid]; - part_uv = &part->sn.uv; + switch (msg_hdr->type) { + case XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV: + /* syncing of remote_act_state was just done above */ + break; - part_uv->remote_act_state = msg_hdr->act_state; + case XPC_ACTIVATE_MQ_MSG_INC_HEARTBEAT_UV: { + struct xpc_activate_mq_msg_heartbeat_req_uv *msg; - switch (msg_hdr->type) { - case XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV: - /* syncing of remote_act_state was just done above */ - break; + msg = container_of(msg_hdr, + struct xpc_activate_mq_msg_heartbeat_req_uv, + hdr); + part_uv->heartbeat = msg->heartbeat; + break; + } + case XPC_ACTIVATE_MQ_MSG_OFFLINE_HEARTBEAT_UV: { + struct xpc_activate_mq_msg_heartbeat_req_uv *msg; + + msg = container_of(msg_hdr, + struct xpc_activate_mq_msg_heartbeat_req_uv, + hdr); + part_uv->heartbeat = msg->heartbeat; + + spin_lock_irqsave(&part_uv->flags_lock, irq_flags); + part_uv->flags |= XPC_P_HEARTBEAT_OFFLINE_UV; + spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); + break; + } + case XPC_ACTIVATE_MQ_MSG_ONLINE_HEARTBEAT_UV: { + struct xpc_activate_mq_msg_heartbeat_req_uv *msg; + + msg = container_of(msg_hdr, + struct xpc_activate_mq_msg_heartbeat_req_uv, + hdr); + part_uv->heartbeat = msg->heartbeat; + + spin_lock_irqsave(&part_uv->flags_lock, irq_flags); + part_uv->flags &= ~XPC_P_HEARTBEAT_OFFLINE_UV; + spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); + break; + } + case XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV: { + struct xpc_activate_mq_msg_activate_req_uv *msg; - case XPC_ACTIVATE_MQ_MSG_INC_HEARTBEAT_UV: { - struct xpc_activate_mq_msg_heartbeat_req_uv *msg; + /* + * ??? Do we deal here with ts_jiffies being different + * ??? if act_state != XPC_P_AS_INACTIVE instead of + * ??? below? + */ + msg = container_of(msg_hdr, struct + xpc_activate_mq_msg_activate_req_uv, hdr); - msg = (struct xpc_activate_mq_msg_heartbeat_req_uv *) - msg_hdr; - part_uv->heartbeat = msg->heartbeat; - break; - } - case XPC_ACTIVATE_MQ_MSG_OFFLINE_HEARTBEAT_UV: { - struct xpc_activate_mq_msg_heartbeat_req_uv *msg; - - msg = (struct xpc_activate_mq_msg_heartbeat_req_uv *) - msg_hdr; - part_uv->heartbeat = msg->heartbeat; - spin_lock_irqsave(&part_uv->flags_lock, irq_flags); - part_uv->flags |= XPC_P_HEARTBEAT_OFFLINE_UV; - spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); - break; - } - case XPC_ACTIVATE_MQ_MSG_ONLINE_HEARTBEAT_UV: { - struct xpc_activate_mq_msg_heartbeat_req_uv *msg; - - msg = (struct xpc_activate_mq_msg_heartbeat_req_uv *) - msg_hdr; - part_uv->heartbeat = msg->heartbeat; - spin_lock_irqsave(&part_uv->flags_lock, irq_flags); - part_uv->flags &= ~XPC_P_HEARTBEAT_OFFLINE_UV; - spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); - break; - } - case XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV: { - struct xpc_activate_mq_msg_activate_req_uv *msg; - - /* - * ??? Do we deal here with ts_jiffies being different - * ??? if act_state != XPC_P_AS_INACTIVE instead of - * ??? below? - */ - msg = (struct xpc_activate_mq_msg_activate_req_uv *) - msg_hdr; - spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, - irq_flags); - if (part_uv->act_state_req == 0) - xpc_activate_IRQ_rcvd++; - part_uv->act_state_req = XPC_P_ASR_ACTIVATE_UV; - part->remote_rp_pa = msg->rp_gpa; /* !!! _pa is _gpa */ - part->remote_rp_ts_jiffies = msg_hdr->rp_ts_jiffies; - part_uv->remote_activate_mq_gpa = msg->activate_mq_gpa; - spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, - irq_flags); - wakeup_hb_checker++; - break; - } - case XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV: { - struct xpc_activate_mq_msg_deactivate_req_uv *msg; - - msg = (struct xpc_activate_mq_msg_deactivate_req_uv *) - msg_hdr; - spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, - irq_flags); - if (part_uv->act_state_req == 0) - xpc_activate_IRQ_rcvd++; - part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV; - part_uv->reason = msg->reason; - spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, - irq_flags); - wakeup_hb_checker++; - break; - } - case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV: { - struct xpc_activate_mq_msg_chctl_closerequest_uv *msg; + spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); + if (part_uv->act_state_req == 0) + xpc_activate_IRQ_rcvd++; + part_uv->act_state_req = XPC_P_ASR_ACTIVATE_UV; + part->remote_rp_pa = msg->rp_gpa; /* !!! _pa is _gpa */ + part->remote_rp_ts_jiffies = msg_hdr->rp_ts_jiffies; + part_uv->remote_activate_mq_gpa = msg->activate_mq_gpa; + spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); - msg = (struct xpc_activate_mq_msg_chctl_closerequest_uv - *)msg_hdr; - args = &part->remote_openclose_args[msg->ch_number]; - args->reason = msg->reason; + (*wakeup_hb_checker)++; + break; + } + case XPC_ACTIVATE_MQ_MSG_DEACTIVATE_REQ_UV: { + struct xpc_activate_mq_msg_deactivate_req_uv *msg; - spin_lock_irqsave(&part->chctl_lock, irq_flags); - part->chctl.flags[msg->ch_number] |= - XPC_CHCTL_CLOSEREQUEST; - spin_unlock_irqrestore(&part->chctl_lock, irq_flags); + msg = container_of(msg_hdr, struct + xpc_activate_mq_msg_deactivate_req_uv, hdr); - xpc_wakeup_channel_mgr(part); - break; - } - case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV: { - struct xpc_activate_mq_msg_chctl_closereply_uv *msg; + spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); + if (part_uv->act_state_req == 0) + xpc_activate_IRQ_rcvd++; + part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV; + part_uv->reason = msg->reason; + spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); + + (*wakeup_hb_checker)++; + return; + } + case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV: { + struct xpc_activate_mq_msg_chctl_closerequest_uv *msg; - msg = (struct xpc_activate_mq_msg_chctl_closereply_uv *) - msg_hdr; + msg = container_of(msg_hdr, struct + xpc_activate_mq_msg_chctl_closerequest_uv, + hdr); + args = &part->remote_openclose_args[msg->ch_number]; + args->reason = msg->reason; - spin_lock_irqsave(&part->chctl_lock, irq_flags); - part->chctl.flags[msg->ch_number] |= - XPC_CHCTL_CLOSEREPLY; - spin_unlock_irqrestore(&part->chctl_lock, irq_flags); + spin_lock_irqsave(&part->chctl_lock, irq_flags); + part->chctl.flags[msg->ch_number] |= XPC_CHCTL_CLOSEREQUEST; + spin_unlock_irqrestore(&part->chctl_lock, irq_flags); - xpc_wakeup_channel_mgr(part); - break; - } - case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV: { - struct xpc_activate_mq_msg_chctl_openrequest_uv *msg; + xpc_wakeup_channel_mgr(part); + break; + } + case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV: { + struct xpc_activate_mq_msg_chctl_closereply_uv *msg; - msg = (struct xpc_activate_mq_msg_chctl_openrequest_uv - *)msg_hdr; - args = &part->remote_openclose_args[msg->ch_number]; - args->msg_size = msg->msg_size; - args->local_nentries = msg->local_nentries; + msg = container_of(msg_hdr, struct + xpc_activate_mq_msg_chctl_closereply_uv, + hdr); - spin_lock_irqsave(&part->chctl_lock, irq_flags); - part->chctl.flags[msg->ch_number] |= - XPC_CHCTL_OPENREQUEST; - spin_unlock_irqrestore(&part->chctl_lock, irq_flags); + spin_lock_irqsave(&part->chctl_lock, irq_flags); + part->chctl.flags[msg->ch_number] |= XPC_CHCTL_CLOSEREPLY; + spin_unlock_irqrestore(&part->chctl_lock, irq_flags); - xpc_wakeup_channel_mgr(part); - break; - } - case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV: { - struct xpc_activate_mq_msg_chctl_openreply_uv *msg; - - msg = (struct xpc_activate_mq_msg_chctl_openreply_uv *) - msg_hdr; - args = &part->remote_openclose_args[msg->ch_number]; - args->remote_nentries = msg->remote_nentries; - args->local_nentries = msg->local_nentries; - args->local_msgqueue_pa = msg->local_notify_mq_gpa; - - spin_lock_irqsave(&part->chctl_lock, irq_flags); - part->chctl.flags[msg->ch_number] |= - XPC_CHCTL_OPENREPLY; - spin_unlock_irqrestore(&part->chctl_lock, irq_flags); - - xpc_wakeup_channel_mgr(part); - break; - } - case XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV: - spin_lock_irqsave(&part_uv->flags_lock, irq_flags); - part_uv->flags |= XPC_P_ENGAGED_UV; - spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); - break; + xpc_wakeup_channel_mgr(part); + break; + } + case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV: { + struct xpc_activate_mq_msg_chctl_openrequest_uv *msg; + + msg = container_of(msg_hdr, struct + xpc_activate_mq_msg_chctl_openrequest_uv, + hdr); + args = &part->remote_openclose_args[msg->ch_number]; + args->entry_size = msg->entry_size; + args->local_nentries = msg->local_nentries; + + spin_lock_irqsave(&part->chctl_lock, irq_flags); + part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENREQUEST; + spin_unlock_irqrestore(&part->chctl_lock, irq_flags); + + xpc_wakeup_channel_mgr(part); + break; + } + case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV: { + struct xpc_activate_mq_msg_chctl_openreply_uv *msg; + + msg = container_of(msg_hdr, struct + xpc_activate_mq_msg_chctl_openreply_uv, hdr); + args = &part->remote_openclose_args[msg->ch_number]; + args->remote_nentries = msg->remote_nentries; + args->local_nentries = msg->local_nentries; + args->local_msgqueue_pa = msg->local_notify_mq_gpa; + + spin_lock_irqsave(&part->chctl_lock, irq_flags); + part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENREPLY; + spin_unlock_irqrestore(&part->chctl_lock, irq_flags); + + xpc_wakeup_channel_mgr(part); + break; + } + case XPC_ACTIVATE_MQ_MSG_MARK_ENGAGED_UV: + spin_lock_irqsave(&part_uv->flags_lock, irq_flags); + part_uv->flags |= XPC_P_ENGAGED_UV; + spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); + break; + + case XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV: + spin_lock_irqsave(&part_uv->flags_lock, irq_flags); + part_uv->flags &= ~XPC_P_ENGAGED_UV; + spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); + break; + + default: + dev_err(xpc_part, "received unknown activate_mq msg type=%d " + "from partition=%d\n", msg_hdr->type, XPC_PARTID(part)); + + /* get hb checker to deactivate from the remote partition */ + spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); + if (part_uv->act_state_req == 0) + xpc_activate_IRQ_rcvd++; + part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV; + part_uv->reason = xpBadMsgType; + spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); - case XPC_ACTIVATE_MQ_MSG_MARK_DISENGAGED_UV: - spin_lock_irqsave(&part_uv->flags_lock, irq_flags); - part_uv->flags &= ~XPC_P_ENGAGED_UV; - spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); - break; + (*wakeup_hb_checker)++; + return; + } - default: - dev_err(xpc_part, "received unknown activate_mq msg " - "type=%d from partition=%d\n", msg_hdr->type, - partid); - } + if (msg_hdr->rp_ts_jiffies != part->remote_rp_ts_jiffies && + part->remote_rp_ts_jiffies != 0) { + /* + * ??? Does what we do here need to be sensitive to + * ??? act_state or remote_act_state? + */ + spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); + if (part_uv->act_state_req == 0) + xpc_activate_IRQ_rcvd++; + part_uv->act_state_req = XPC_P_ASR_REACTIVATE_UV; + spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); - if (msg_hdr->rp_ts_jiffies != part->remote_rp_ts_jiffies && - part->remote_rp_ts_jiffies != 0) { - /* - * ??? Does what we do here need to be sensitive to - * ??? act_state or remote_act_state? - */ - spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, - irq_flags); - if (part_uv->act_state_req == 0) - xpc_activate_IRQ_rcvd++; - part_uv->act_state_req = XPC_P_ASR_REACTIVATE_UV; - spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, - irq_flags); - wakeup_hb_checker++; + (*wakeup_hb_checker)++; + } +} + +static irqreturn_t +xpc_handle_activate_IRQ_uv(int irq, void *dev_id) +{ + struct xpc_activate_mq_msghdr_uv *msg_hdr; + short partid; + struct xpc_partition *part; + int wakeup_hb_checker = 0; + + while ((msg_hdr = gru_get_next_message(xpc_activate_mq_uv)) != NULL) { + + partid = msg_hdr->partid; + if (partid < 0 || partid >= XP_MAX_NPARTITIONS_UV) { + dev_err(xpc_part, "xpc_handle_activate_IRQ_uv() " + "received invalid partid=0x%x in message\n", + partid); + } else { + part = &xpc_partitions[partid]; + if (xpc_part_ref(part)) { + xpc_handle_activate_mq_msg_uv(part, msg_hdr, + &wakeup_hb_checker); + xpc_part_deref(part); + } } gru_free_message(xpc_activate_mq_uv, msg_hdr); @@ -616,14 +643,82 @@ xpc_request_partition_deactivation_uv(struct xpc_partition *part) } } +static void +xpc_cancel_partition_deactivation_request_uv(struct xpc_partition *part) +{ + /* nothing needs to be done */ + return; +} + +static void +xpc_init_fifo_uv(struct xpc_fifo_head_uv *head) +{ + head->first = NULL; + head->last = NULL; + spin_lock_init(&head->lock); + head->n_entries = 0; +} + +static void * +xpc_get_fifo_entry_uv(struct xpc_fifo_head_uv *head) +{ + unsigned long irq_flags; + struct xpc_fifo_entry_uv *first; + + spin_lock_irqsave(&head->lock, irq_flags); + first = head->first; + if (head->first != NULL) { + head->first = first->next; + if (head->first == NULL) + head->last = NULL; + } + head->n_entries++; + spin_unlock_irqrestore(&head->lock, irq_flags); + first->next = NULL; + return first; +} + +static void +xpc_put_fifo_entry_uv(struct xpc_fifo_head_uv *head, + struct xpc_fifo_entry_uv *last) +{ + unsigned long irq_flags; + + last->next = NULL; + spin_lock_irqsave(&head->lock, irq_flags); + if (head->last != NULL) + head->last->next = last; + else + head->first = last; + head->last = last; + head->n_entries--; + BUG_ON(head->n_entries < 0); + spin_unlock_irqrestore(&head->lock, irq_flags); +} + +static int +xpc_n_of_fifo_entries_uv(struct xpc_fifo_head_uv *head) +{ + return head->n_entries; +} + /* * Setup the channel structures that are uv specific. */ static enum xp_retval xpc_setup_ch_structures_sn_uv(struct xpc_partition *part) { - /* !!! this function needs fleshing out */ - return xpUnsupported; + struct xpc_channel_uv *ch_uv; + int ch_number; + + for (ch_number = 0; ch_number < part->nchannels; ch_number++) { + ch_uv = &part->channels[ch_number].sn.uv; + + xpc_init_fifo_uv(&ch_uv->msg_slot_free_list); + xpc_init_fifo_uv(&ch_uv->recv_msg_list); + } + + return xpSuccess; } /* @@ -632,7 +727,7 @@ xpc_setup_ch_structures_sn_uv(struct xpc_partition *part) static void xpc_teardown_ch_structures_sn_uv(struct xpc_partition *part) { - /* !!! this function needs fleshing out */ + /* nothing needs to be done */ return; } @@ -679,21 +774,115 @@ xpc_get_chctl_all_flags_uv(struct xpc_partition *part) return chctl.all_flags; } +static enum xp_retval +xpc_allocate_send_msg_slot_uv(struct xpc_channel *ch) +{ + struct xpc_channel_uv *ch_uv = &ch->sn.uv; + struct xpc_send_msg_slot_uv *msg_slot; + unsigned long irq_flags; + int nentries; + int entry; + size_t nbytes; + + for (nentries = ch->local_nentries; nentries > 0; nentries--) { + nbytes = nentries * sizeof(struct xpc_send_msg_slot_uv); + ch_uv->send_msg_slots = kzalloc(nbytes, GFP_KERNEL); + if (ch_uv->send_msg_slots == NULL) + continue; + + for (entry = 0; entry < nentries; entry++) { + msg_slot = &ch_uv->send_msg_slots[entry]; + + msg_slot->msg_slot_number = entry; + xpc_put_fifo_entry_uv(&ch_uv->msg_slot_free_list, + &msg_slot->next); + } + + spin_lock_irqsave(&ch->lock, irq_flags); + if (nentries < ch->local_nentries) + ch->local_nentries = nentries; + spin_unlock_irqrestore(&ch->lock, irq_flags); + return xpSuccess; + } + + return xpNoMemory; +} + +static enum xp_retval +xpc_allocate_recv_msg_slot_uv(struct xpc_channel *ch) +{ + struct xpc_channel_uv *ch_uv = &ch->sn.uv; + struct xpc_notify_mq_msg_uv *msg_slot; + unsigned long irq_flags; + int nentries; + int entry; + size_t nbytes; + + for (nentries = ch->remote_nentries; nentries > 0; nentries--) { + nbytes = nentries * ch->entry_size; + ch_uv->recv_msg_slots = kzalloc(nbytes, GFP_KERNEL); + if (ch_uv->recv_msg_slots == NULL) + continue; + + for (entry = 0; entry < nentries; entry++) { + msg_slot = ch_uv->recv_msg_slots + entry * + ch->entry_size; + + msg_slot->hdr.msg_slot_number = entry; + } + + spin_lock_irqsave(&ch->lock, irq_flags); + if (nentries < ch->remote_nentries) + ch->remote_nentries = nentries; + spin_unlock_irqrestore(&ch->lock, irq_flags); + return xpSuccess; + } + + return xpNoMemory; +} + +/* + * Allocate msg_slots associated with the channel. + */ static enum xp_retval xpc_setup_msg_structures_uv(struct xpc_channel *ch) { - /* !!! this function needs fleshing out */ - return xpUnsupported; + static enum xp_retval ret; + struct xpc_channel_uv *ch_uv = &ch->sn.uv; + + DBUG_ON(ch->flags & XPC_C_SETUP); + + ret = xpc_allocate_send_msg_slot_uv(ch); + if (ret == xpSuccess) { + + ret = xpc_allocate_recv_msg_slot_uv(ch); + if (ret != xpSuccess) { + kfree(ch_uv->send_msg_slots); + xpc_init_fifo_uv(&ch_uv->msg_slot_free_list); + } + } + return ret; } +/* + * Free up msg_slots and clear other stuff that were setup for the specified + * channel. + */ static void xpc_teardown_msg_structures_uv(struct xpc_channel *ch) { struct xpc_channel_uv *ch_uv = &ch->sn.uv; + DBUG_ON(!spin_is_locked(&ch->lock)); + ch_uv->remote_notify_mq_gpa = 0; - /* !!! this function needs fleshing out */ + if (ch->flags & XPC_C_SETUP) { + xpc_init_fifo_uv(&ch_uv->msg_slot_free_list); + kfree(ch_uv->send_msg_slots); + xpc_init_fifo_uv(&ch_uv->recv_msg_list); + kfree(ch_uv->recv_msg_slots); + } } static void @@ -723,7 +912,7 @@ xpc_send_chctl_openrequest_uv(struct xpc_channel *ch, unsigned long *irq_flags) struct xpc_activate_mq_msg_chctl_openrequest_uv msg; msg.ch_number = ch->number; - msg.msg_size = ch->msg_size; + msg.entry_size = ch->entry_size; msg.local_nentries = ch->local_nentries; xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg), XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV); @@ -742,6 +931,18 @@ xpc_send_chctl_openreply_uv(struct xpc_channel *ch, unsigned long *irq_flags) XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV); } +static void +xpc_send_chctl_local_msgrequest_uv(struct xpc_partition *part, int ch_number) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&part->chctl_lock, irq_flags); + part->chctl.flags[ch_number] |= XPC_CHCTL_MSGREQUEST; + spin_unlock_irqrestore(&part->chctl_lock, irq_flags); + + xpc_wakeup_channel_mgr(part); +} + static void xpc_save_remote_msgqueue_pa_uv(struct xpc_channel *ch, unsigned long msgqueue_pa) @@ -798,11 +999,358 @@ xpc_any_partition_engaged_uv(void) return 0; } -static struct xpc_msg * -xpc_get_deliverable_msg_uv(struct xpc_channel *ch) +static enum xp_retval +xpc_allocate_msg_slot_uv(struct xpc_channel *ch, u32 flags, + struct xpc_send_msg_slot_uv **address_of_msg_slot) +{ + enum xp_retval ret; + struct xpc_send_msg_slot_uv *msg_slot; + struct xpc_fifo_entry_uv *entry; + + while (1) { + entry = xpc_get_fifo_entry_uv(&ch->sn.uv.msg_slot_free_list); + if (entry != NULL) + break; + + if (flags & XPC_NOWAIT) + return xpNoWait; + + ret = xpc_allocate_msg_wait(ch); + if (ret != xpInterrupted && ret != xpTimeout) + return ret; + } + + msg_slot = container_of(entry, struct xpc_send_msg_slot_uv, next); + *address_of_msg_slot = msg_slot; + return xpSuccess; +} + +static void +xpc_free_msg_slot_uv(struct xpc_channel *ch, + struct xpc_send_msg_slot_uv *msg_slot) +{ + xpc_put_fifo_entry_uv(&ch->sn.uv.msg_slot_free_list, &msg_slot->next); + + /* wakeup anyone waiting for a free msg slot */ + if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) + wake_up(&ch->msg_allocate_wq); +} + +static void +xpc_notify_sender_uv(struct xpc_channel *ch, + struct xpc_send_msg_slot_uv *msg_slot, + enum xp_retval reason) +{ + xpc_notify_func func = msg_slot->func; + + if (func != NULL && cmpxchg(&msg_slot->func, func, NULL) == func) { + + atomic_dec(&ch->n_to_notify); + + dev_dbg(xpc_chan, "msg_slot->func() called, msg_slot=0x%p " + "msg_slot_number=%d partid=%d channel=%d\n", msg_slot, + msg_slot->msg_slot_number, ch->partid, ch->number); + + func(reason, ch->partid, ch->number, msg_slot->key); + + dev_dbg(xpc_chan, "msg_slot->func() returned, msg_slot=0x%p " + "msg_slot_number=%d partid=%d channel=%d\n", msg_slot, + msg_slot->msg_slot_number, ch->partid, ch->number); + } +} + +static void +xpc_handle_notify_mq_ack_uv(struct xpc_channel *ch, + struct xpc_notify_mq_msg_uv *msg) +{ + struct xpc_send_msg_slot_uv *msg_slot; + int entry = msg->hdr.msg_slot_number % ch->local_nentries; + + msg_slot = &ch->sn.uv.send_msg_slots[entry]; + + BUG_ON(msg_slot->msg_slot_number != msg->hdr.msg_slot_number); + msg_slot->msg_slot_number += ch->local_nentries; + + if (msg_slot->func != NULL) + xpc_notify_sender_uv(ch, msg_slot, xpMsgDelivered); + + xpc_free_msg_slot_uv(ch, msg_slot); +} + +static void +xpc_handle_notify_mq_msg_uv(struct xpc_partition *part, + struct xpc_notify_mq_msg_uv *msg) +{ + struct xpc_partition_uv *part_uv = &part->sn.uv; + struct xpc_channel *ch; + struct xpc_channel_uv *ch_uv; + struct xpc_notify_mq_msg_uv *msg_slot; + unsigned long irq_flags; + int ch_number = msg->hdr.ch_number; + + if (unlikely(ch_number >= part->nchannels)) { + dev_err(xpc_part, "xpc_handle_notify_IRQ_uv() received invalid " + "channel number=0x%x in message from partid=%d\n", + ch_number, XPC_PARTID(part)); + + /* get hb checker to deactivate from the remote partition */ + spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); + if (part_uv->act_state_req == 0) + xpc_activate_IRQ_rcvd++; + part_uv->act_state_req = XPC_P_ASR_DEACTIVATE_UV; + part_uv->reason = xpBadChannelNumber; + spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); + + wake_up_interruptible(&xpc_activate_IRQ_wq); + return; + } + + ch = &part->channels[ch_number]; + xpc_msgqueue_ref(ch); + + if (!(ch->flags & XPC_C_CONNECTED)) { + xpc_msgqueue_deref(ch); + return; + } + + /* see if we're really dealing with an ACK for a previously sent msg */ + if (msg->hdr.size == 0) { + xpc_handle_notify_mq_ack_uv(ch, msg); + xpc_msgqueue_deref(ch); + return; + } + + /* we're dealing with a normal message sent via the notify_mq */ + ch_uv = &ch->sn.uv; + + msg_slot = (struct xpc_notify_mq_msg_uv *)((u64)ch_uv->recv_msg_slots + + (msg->hdr.msg_slot_number % ch->remote_nentries) * + ch->entry_size); + + BUG_ON(msg->hdr.msg_slot_number != msg_slot->hdr.msg_slot_number); + BUG_ON(msg_slot->hdr.size != 0); + + memcpy(msg_slot, msg, msg->hdr.size); + + xpc_put_fifo_entry_uv(&ch_uv->recv_msg_list, &msg_slot->hdr.u.next); + + if (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) { + /* + * If there is an existing idle kthread get it to deliver + * the payload, otherwise we'll have to get the channel mgr + * for this partition to create a kthread to do the delivery. + */ + if (atomic_read(&ch->kthreads_idle) > 0) + wake_up_nr(&ch->idle_wq, 1); + else + xpc_send_chctl_local_msgrequest_uv(part, ch->number); + } + xpc_msgqueue_deref(ch); +} + +static irqreturn_t +xpc_handle_notify_IRQ_uv(int irq, void *dev_id) +{ + struct xpc_notify_mq_msg_uv *msg; + short partid; + struct xpc_partition *part; + + while ((msg = gru_get_next_message(xpc_notify_mq_uv)) != NULL) { + + partid = msg->hdr.partid; + if (partid < 0 || partid >= XP_MAX_NPARTITIONS_UV) { + dev_err(xpc_part, "xpc_handle_notify_IRQ_uv() received " + "invalid partid=0x%x in message\n", partid); + } else { + part = &xpc_partitions[partid]; + + if (xpc_part_ref(part)) { + xpc_handle_notify_mq_msg_uv(part, msg); + xpc_part_deref(part); + } + } + + gru_free_message(xpc_notify_mq_uv, msg); + } + + return IRQ_HANDLED; +} + +static int +xpc_n_of_deliverable_payloads_uv(struct xpc_channel *ch) +{ + return xpc_n_of_fifo_entries_uv(&ch->sn.uv.recv_msg_list); +} + +static void +xpc_process_msg_chctl_flags_uv(struct xpc_partition *part, int ch_number) +{ + struct xpc_channel *ch = &part->channels[ch_number]; + int ndeliverable_payloads; + + xpc_msgqueue_ref(ch); + + ndeliverable_payloads = xpc_n_of_deliverable_payloads_uv(ch); + + if (ndeliverable_payloads > 0 && + (ch->flags & XPC_C_CONNECTED) && + (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE)) { + + xpc_activate_kthreads(ch, ndeliverable_payloads); + } + + xpc_msgqueue_deref(ch); +} + +static enum xp_retval +xpc_send_payload_uv(struct xpc_channel *ch, u32 flags, void *payload, + u16 payload_size, u8 notify_type, xpc_notify_func func, + void *key) +{ + enum xp_retval ret = xpSuccess; + struct xpc_send_msg_slot_uv *msg_slot = NULL; + struct xpc_notify_mq_msg_uv *msg; + u8 msg_buffer[XPC_NOTIFY_MSG_SIZE_UV]; + size_t msg_size; + + DBUG_ON(notify_type != XPC_N_CALL); + + msg_size = sizeof(struct xpc_notify_mq_msghdr_uv) + payload_size; + if (msg_size > ch->entry_size) + return xpPayloadTooBig; + + xpc_msgqueue_ref(ch); + + if (ch->flags & XPC_C_DISCONNECTING) { + ret = ch->reason; + goto out_1; + } + if (!(ch->flags & XPC_C_CONNECTED)) { + ret = xpNotConnected; + goto out_1; + } + + ret = xpc_allocate_msg_slot_uv(ch, flags, &msg_slot); + if (ret != xpSuccess) + goto out_1; + + if (func != NULL) { + atomic_inc(&ch->n_to_notify); + + msg_slot->key = key; + wmb(); /* a non-NULL func must hit memory after the key */ + msg_slot->func = func; + + if (ch->flags & XPC_C_DISCONNECTING) { + ret = ch->reason; + goto out_2; + } + } + + msg = (struct xpc_notify_mq_msg_uv *)&msg_buffer; + msg->hdr.partid = xp_partition_id; + msg->hdr.ch_number = ch->number; + msg->hdr.size = msg_size; + msg->hdr.msg_slot_number = msg_slot->msg_slot_number; + memcpy(&msg->payload, payload, payload_size); + + ret = xpc_send_gru_msg(ch->sn.uv.remote_notify_mq_gpa, msg, msg_size); + if (ret == xpSuccess) + goto out_1; + + XPC_DEACTIVATE_PARTITION(&xpc_partitions[ch->partid], ret); +out_2: + if (func != NULL) { + /* + * Try to NULL the msg_slot's func field. If we fail, then + * xpc_notify_senders_of_disconnect_uv() beat us to it, in which + * case we need to pretend we succeeded to send the message + * since the user will get a callout for the disconnect error + * by xpc_notify_senders_of_disconnect_uv(), and to also get an + * error returned here will confuse them. Additionally, since + * in this case the channel is being disconnected we don't need + * to put the the msg_slot back on the free list. + */ + if (cmpxchg(&msg_slot->func, func, NULL) != func) { + ret = xpSuccess; + goto out_1; + } + + msg_slot->key = NULL; + atomic_dec(&ch->n_to_notify); + } + xpc_free_msg_slot_uv(ch, msg_slot); +out_1: + xpc_msgqueue_deref(ch); + return ret; +} + +/* + * Tell the callers of xpc_send_notify() that the status of their payloads + * is unknown because the channel is now disconnecting. + * + * We don't worry about putting these msg_slots on the free list since the + * msg_slots themselves are about to be kfree'd. + */ +static void +xpc_notify_senders_of_disconnect_uv(struct xpc_channel *ch) +{ + struct xpc_send_msg_slot_uv *msg_slot; + int entry; + + DBUG_ON(!(ch->flags & XPC_C_DISCONNECTING)); + + for (entry = 0; entry < ch->local_nentries; entry++) { + + if (atomic_read(&ch->n_to_notify) == 0) + break; + + msg_slot = &ch->sn.uv.send_msg_slots[entry]; + if (msg_slot->func != NULL) + xpc_notify_sender_uv(ch, msg_slot, ch->reason); + } +} + +/* + * Get the next deliverable message's payload. + */ +static void * +xpc_get_deliverable_payload_uv(struct xpc_channel *ch) +{ + struct xpc_fifo_entry_uv *entry; + struct xpc_notify_mq_msg_uv *msg; + void *payload = NULL; + + if (!(ch->flags & XPC_C_DISCONNECTING)) { + entry = xpc_get_fifo_entry_uv(&ch->sn.uv.recv_msg_list); + if (entry != NULL) { + msg = container_of(entry, struct xpc_notify_mq_msg_uv, + hdr.u.next); + payload = &msg->payload; + } + } + return payload; +} + +static void +xpc_received_payload_uv(struct xpc_channel *ch, void *payload) { - /* !!! this function needs fleshing out */ - return NULL; + struct xpc_notify_mq_msg_uv *msg; + enum xp_retval ret; + + msg = container_of(payload, struct xpc_notify_mq_msg_uv, payload); + + /* return an ACK to the sender of this message */ + + msg->hdr.partid = xp_partition_id; + msg->hdr.size = 0; /* size of zero indicates this is an ACK */ + + ret = xpc_send_gru_msg(ch->sn.uv.remote_notify_mq_gpa, msg, + sizeof(struct xpc_notify_mq_msghdr_uv)); + if (ret != xpSuccess) + XPC_DEACTIVATE_PARTITION(&xpc_partitions[ch->partid], ret); + + msg->hdr.msg_slot_number += ch->remote_nentries; } int @@ -824,6 +1372,8 @@ xpc_init_uv(void) xpc_request_partition_reactivation_uv; xpc_request_partition_deactivation = xpc_request_partition_deactivation_uv; + xpc_cancel_partition_deactivation_request = + xpc_cancel_partition_deactivation_request_uv; xpc_setup_ch_structures_sn = xpc_setup_ch_structures_sn_uv; xpc_teardown_ch_structures_sn = xpc_teardown_ch_structures_sn_uv; @@ -848,7 +1398,18 @@ xpc_init_uv(void) xpc_partition_engaged = xpc_partition_engaged_uv; xpc_any_partition_engaged = xpc_any_partition_engaged_uv; - xpc_get_deliverable_msg = xpc_get_deliverable_msg_uv; + xpc_n_of_deliverable_payloads = xpc_n_of_deliverable_payloads_uv; + xpc_process_msg_chctl_flags = xpc_process_msg_chctl_flags_uv; + xpc_send_payload = xpc_send_payload_uv; + xpc_notify_senders_of_disconnect = xpc_notify_senders_of_disconnect_uv; + xpc_get_deliverable_payload = xpc_get_deliverable_payload_uv; + xpc_received_payload = xpc_received_payload_uv; + + if (sizeof(struct xpc_notify_mq_msghdr_uv) > XPC_MSG_HDR_MAX_SIZE) { + dev_err(xpc_part, "xpc_notify_mq_msghdr_uv is larger than %d\n", + XPC_MSG_HDR_MAX_SIZE); + return -E2BIG; + } /* ??? The cpuid argument's value is 0, is that what we want? */ /* !!! The irq argument's value isn't correct. */ @@ -857,12 +1418,26 @@ xpc_init_uv(void) if (xpc_activate_mq_uv == NULL) return -ENOMEM; + /* ??? The cpuid argument's value is 0, is that what we want? */ + /* !!! The irq argument's value isn't correct. */ + xpc_notify_mq_uv = xpc_create_gru_mq_uv(XPC_NOTIFY_MQ_SIZE_UV, 0, 0, + xpc_handle_notify_IRQ_uv); + if (xpc_notify_mq_uv == NULL) { + /* !!! The irq argument's value isn't correct. */ + xpc_destroy_gru_mq_uv(xpc_activate_mq_uv, + XPC_ACTIVATE_MQ_SIZE_UV, 0); + return -ENOMEM; + } + return 0; } void xpc_exit_uv(void) { + /* !!! The irq argument's value isn't correct. */ + xpc_destroy_gru_mq_uv(xpc_notify_mq_uv, XPC_NOTIFY_MQ_SIZE_UV, 0); + /* !!! The irq argument's value isn't correct. */ xpc_destroy_gru_mq_uv(xpc_activate_mq_uv, XPC_ACTIVATE_MQ_SIZE_UV, 0); } diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 4f5d6223011..71513b3af70 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -57,11 +57,10 @@ struct xpnet_message { * * XPC expects each message to exist in an individual cacheline. */ -#define XPNET_MSG_SIZE (L1_CACHE_BYTES - XPC_MSG_PAYLOAD_OFFSET) +#define XPNET_MSG_SIZE XPC_MSG_PAYLOAD_MAX_SIZE #define XPNET_MSG_DATA_MAX \ - (XPNET_MSG_SIZE - (u64)(&((struct xpnet_message *)0)->data)) -#define XPNET_MSG_ALIGNED_SIZE (L1_CACHE_ALIGN(XPNET_MSG_SIZE)) -#define XPNET_MSG_NENTRIES (PAGE_SIZE / XPNET_MSG_ALIGNED_SIZE) + (XPNET_MSG_SIZE - offsetof(struct xpnet_message, data)) +#define XPNET_MSG_NENTRIES (PAGE_SIZE / XPC_MSG_MAX_SIZE) #define XPNET_MAX_KTHREADS (XPNET_MSG_NENTRIES + 1) #define XPNET_MAX_IDLE_KTHREADS (XPNET_MSG_NENTRIES + 1) @@ -408,6 +407,7 @@ xpnet_send(struct sk_buff *skb, struct xpnet_pending_msg *queued_msg, { u8 msg_buffer[XPNET_MSG_SIZE]; struct xpnet_message *msg = (struct xpnet_message *)&msg_buffer; + u16 msg_size = sizeof(struct xpnet_message); enum xp_retval ret; msg->embedded_bytes = embedded_bytes; @@ -417,6 +417,7 @@ xpnet_send(struct sk_buff *skb, struct xpnet_pending_msg *queued_msg, &msg->data, skb->data, (size_t)embedded_bytes); skb_copy_from_linear_data(skb, &msg->data, (size_t)embedded_bytes); + msg_size += embedded_bytes - 1; } else { msg->version = XPNET_VERSION; } @@ -435,7 +436,7 @@ xpnet_send(struct sk_buff *skb, struct xpnet_pending_msg *queued_msg, atomic_inc(&queued_msg->use_count); ret = xpc_send_notify(dest_partid, XPC_NET_CHANNEL, XPC_NOWAIT, msg, - XPNET_MSG_SIZE, xpnet_send_completed, queued_msg); + msg_size, xpnet_send_completed, queued_msg); if (unlikely(ret != xpSuccess)) atomic_dec(&queued_msg->use_count); } -- cgit v1.2.3 From d02a4e31ed0385eb34fe49f19d69a860a020ca3c Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Wed, 30 Jul 2008 13:44:55 +0200 Subject: fix NE2000 linkage error Trying to build with CONFIG_NE2000=m fails with: scripts/mod/modpost -o /tmp/tmp/linux-2.6.27-rc1/Module.symvers -S -s ERROR: "NS8390_init" [drivers/net/ne.ko] undefined! This is because the split of 8390 into pausing and non-pausing versions was incompletely propagated to ne.c. This fixes it. Signed-off-by: Mikael Pettersson Signed-off-by: Jeff Garzik --- drivers/net/ne.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 2fec6122c7f..42443d69742 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -536,7 +536,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = eip_poll; #endif - NS8390_init(dev, 0); + NS8390p_init(dev, 0); ret = register_netdev(dev); if (ret) @@ -794,7 +794,7 @@ retry: if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name); ne_reset_8390(dev); - NS8390_init(dev,1); + NS8390p_init(dev, 1); break; } @@ -855,7 +855,7 @@ static int ne_drv_resume(struct platform_device *pdev) if (netif_running(dev)) { ne_reset_8390(dev); - NS8390_init(dev, 1); + NS8390p_init(dev, 1); netif_device_attach(dev); } return 0; -- cgit v1.2.3 From b0ca2a21f769ae255bd6821cbc5af8af797f1da7 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Mon, 30 Jun 2008 11:08:17 +0900 Subject: sh_eth: Add support of SH7763 to sh_eth SH7763 has Ethernet core same as SH7710/SH7712. Positions of some registry are different, but the basic part is the same. I add support of ethernet of sh7763 to sh_eth. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 4 +- drivers/net/sh_eth.c | 202 +++++++++++++++++++----- drivers/net/sh_eth.h | 426 +++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 482 insertions(+), 150 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index fa533c27052..8a03875ec87 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -510,14 +510,14 @@ config STNIC config SH_ETH tristate "Renesas SuperH Ethernet support" depends on SUPERH && \ - (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712) + (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || CPU_SUBTYPE_SH7763) select CRC32 select MII select MDIO_BITBANG select PHYLIB help Renesas SuperH Ethernet device driver. - This driver support SH7710 and SH7712. + This driver support SH7710, SH7712 and SH7763. config SUNLANCE tristate "Sun LANCE support" diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index c69ba1395fa..6a06b9503e4 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -1,7 +1,7 @@ /* * SuperH Ethernet device driver * - * Copyright (C) 2006,2007 Nobuhiro Iwamatsu + * Copyright (C) 2006-2008 Nobuhiro Iwamatsu * Copyright (C) 2008 Renesas Solutions Corp. * * This program is free software; you can redistribute it and/or modify it @@ -143,13 +143,39 @@ static struct mdiobb_ops bb_ops = { .get_mdio_data = sh_get_mdio, }; +/* Chip Reset */ static void sh_eth_reset(struct net_device *ndev) { u32 ioaddr = ndev->base_addr; +#if defined(CONFIG_CPU_SUBTYPE_SH7763) + int cnt = 100; + + ctrl_outl(EDSR_ENALL, ioaddr + EDSR); + ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR); + while (cnt > 0) { + if (!(ctrl_inl(ioaddr + EDMR) & 0x3)) + break; + mdelay(1); + cnt--; + } + if (cnt < 0) + printk(KERN_ERR "Device reset fail\n"); + + /* Table Init */ + ctrl_outl(0x0, ioaddr + TDLAR); + ctrl_outl(0x0, ioaddr + TDFAR); + ctrl_outl(0x0, ioaddr + TDFXR); + ctrl_outl(0x0, ioaddr + TDFFR); + ctrl_outl(0x0, ioaddr + RDLAR); + ctrl_outl(0x0, ioaddr + RDFAR); + ctrl_outl(0x0, ioaddr + RDFXR); + ctrl_outl(0x0, ioaddr + RDFFR); +#else ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR); mdelay(3); ctrl_outl(ctrl_inl(ioaddr + EDMR) & ~EDMR_SRST, ioaddr + EDMR); +#endif } /* free skb and descriptor buffer */ @@ -180,6 +206,7 @@ static void sh_eth_ring_free(struct net_device *ndev) /* format skb and descriptor buffer */ static void sh_eth_ring_format(struct net_device *ndev) { + u32 ioaddr = ndev->base_addr, reserve = 0; struct sh_eth_private *mdp = netdev_priv(ndev); int i; struct sk_buff *skb; @@ -201,9 +228,15 @@ static void sh_eth_ring_format(struct net_device *ndev) mdp->rx_skbuff[i] = skb; if (skb == NULL) break; - skb->dev = ndev; /* Mark as being used by this device. */ + skb->dev = ndev; /* Mark as being used by this device. */ +#if defined(CONFIG_CPU_SUBTYPE_SH7763) + reserve = SH7763_SKB_ALIGN + - ((uint32_t)skb->data & (SH7763_SKB_ALIGN-1)); + if (reserve) + skb_reserve(skb, reserve); +#else skb_reserve(skb, RX_OFFSET); - +#endif /* RX descriptor */ rxdesc = &mdp->rx_ring[i]; rxdesc->addr = (u32)skb->data & ~0x3UL; @@ -211,12 +244,25 @@ static void sh_eth_ring_format(struct net_device *ndev) /* The size of the buffer is 16 byte boundary. */ rxdesc->buffer_length = (mdp->rx_buf_sz + 16) & ~0x0F; + /* Rx descriptor address set */ + if (i == 0) { + ctrl_outl((u32)rxdesc, ioaddr + RDLAR); +#if defined(CONFIG_CPU_SUBTYPE_SH7763) + ctrl_outl((u32)rxdesc, ioaddr + RDFAR); +#endif + } } + /* Rx descriptor address set */ +#if defined(CONFIG_CPU_SUBTYPE_SH7763) + ctrl_outl((u32)rxdesc, ioaddr + RDFXR); + ctrl_outl(0x1, ioaddr + RDFFR); +#endif + mdp->dirty_rx = (u32) (i - RX_RING_SIZE); /* Mark the last entry as wrapping the ring. */ - rxdesc->status |= cpu_to_le32(RC_RDEL); + rxdesc->status |= cpu_to_le32(RD_RDEL); memset(mdp->tx_ring, 0, tx_ringsize); @@ -226,8 +272,21 @@ static void sh_eth_ring_format(struct net_device *ndev) txdesc = &mdp->tx_ring[i]; txdesc->status = cpu_to_le32(TD_TFP); txdesc->buffer_length = 0; + if (i == 0) { + /* Rx descriptor address set */ + ctrl_outl((u32)txdesc, ioaddr + TDLAR); +#if defined(CONFIG_CPU_SUBTYPE_SH7763) + ctrl_outl((u32)txdesc, ioaddr + TDFAR); +#endif + } } + /* Rx descriptor address set */ +#if defined(CONFIG_CPU_SUBTYPE_SH7763) + ctrl_outl((u32)txdesc, ioaddr + TDFXR); + ctrl_outl(0x1, ioaddr + TDFFR); +#endif + txdesc->status |= cpu_to_le32(TD_TDLE); } @@ -311,31 +370,43 @@ static int sh_eth_dev_init(struct net_device *ndev) /* Soft Reset */ sh_eth_reset(ndev); - ctrl_outl(RPADIR_PADS1, ioaddr + RPADIR); /* SH7712-DMA-RX-PAD2 */ + /* Descriptor format */ + sh_eth_ring_format(ndev); + ctrl_outl(RPADIR_INIT, ioaddr + RPADIR); /* all sh_eth int mask */ ctrl_outl(0, ioaddr + EESIPR); - /* FIFO size set */ +#if defined(CONFIG_CPU_SUBTYPE_SH7763) + ctrl_outl(EDMR_EL, ioaddr + EDMR); +#else ctrl_outl(0, ioaddr + EDMR); /* Endian change */ +#endif + /* FIFO size set */ ctrl_outl((FIFO_SIZE_T | FIFO_SIZE_R), ioaddr + FDR); ctrl_outl(0, ioaddr + TFTR); + /* Frame recv control */ ctrl_outl(0, ioaddr + RMCR); rx_int_var = mdp->rx_int_var = DESC_I_RINT8 | DESC_I_RINT5; tx_int_var = mdp->tx_int_var = DESC_I_TINT2; ctrl_outl(rx_int_var | tx_int_var, ioaddr + TRSCER); +#if defined(CONFIG_CPU_SUBTYPE_SH7763) + /* Burst sycle set */ + ctrl_outl(0x800, ioaddr + BCULR); +#endif + ctrl_outl((FIFO_F_D_RFF | FIFO_F_D_RFD), ioaddr + FCFTR); - ctrl_outl(0, ioaddr + TRIMD); - /* Descriptor format */ - sh_eth_ring_format(ndev); +#if !defined(CONFIG_CPU_SUBTYPE_SH7763) + ctrl_outl(0, ioaddr + TRIMD); +#endif - ctrl_outl((u32)mdp->rx_ring, ioaddr + RDLAR); - ctrl_outl((u32)mdp->tx_ring, ioaddr + TDLAR); + /* Recv frame limit set register */ + ctrl_outl(RFLR_VALUE, ioaddr + RFLR); ctrl_outl(ctrl_inl(ioaddr + EESR), ioaddr + EESR); ctrl_outl((DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff), ioaddr + EESIPR); @@ -345,21 +416,26 @@ static int sh_eth_dev_init(struct net_device *ndev) ECMR_ZPF | (mdp->duplex ? ECMR_DM : 0) | ECMR_TE | ECMR_RE; ctrl_outl(val, ioaddr + ECMR); - ctrl_outl(ECSR_BRCRX | ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD | - ECSIPR_MPDIP, ioaddr + ECSR); - ctrl_outl(ECSIPR_BRCRXIP | ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | - ECSIPR_ICDIP | ECSIPR_MPDIP, ioaddr + ECSIPR); + + /* E-MAC Status Register clear */ + ctrl_outl(ECSR_INIT, ioaddr + ECSR); + + /* E-MAC Interrupt Enable register */ + ctrl_outl(ECSIPR_INIT, ioaddr + ECSIPR); /* Set MAC address */ update_mac_address(ndev); /* mask reset */ -#if defined(CONFIG_CPU_SUBTYPE_SH7710) +#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7763) ctrl_outl(APR_AP, ioaddr + APR); ctrl_outl(MPR_MP, ioaddr + MPR); ctrl_outl(TPAUSER_UNLIMITED, ioaddr + TPAUSER); +#endif +#if defined(CONFIG_CPU_SUBTYPE_SH7710) ctrl_outl(BCFR_UNLIMITED, ioaddr + BCFR); #endif + /* Setting the Rx mode will start the Rx process. */ ctrl_outl(EDRRR_R, ioaddr + EDRRR); @@ -407,7 +483,7 @@ static int sh_eth_rx(struct net_device *ndev) int boguscnt = (mdp->dirty_rx + RX_RING_SIZE) - mdp->cur_rx; struct sk_buff *skb; u16 pkt_len = 0; - u32 desc_status; + u32 desc_status, reserve = 0; rxdesc = &mdp->rx_ring[entry]; while (!(rxdesc->status & cpu_to_le32(RD_RACT))) { @@ -454,28 +530,38 @@ static int sh_eth_rx(struct net_device *ndev) for (; mdp->cur_rx - mdp->dirty_rx > 0; mdp->dirty_rx++) { entry = mdp->dirty_rx % RX_RING_SIZE; rxdesc = &mdp->rx_ring[entry]; + /* The size of the buffer is 16 byte boundary. */ + rxdesc->buffer_length = (mdp->rx_buf_sz + 16) & ~0x0F; + if (mdp->rx_skbuff[entry] == NULL) { skb = dev_alloc_skb(mdp->rx_buf_sz); mdp->rx_skbuff[entry] = skb; if (skb == NULL) break; /* Better luck next round. */ skb->dev = ndev; +#if defined(CONFIG_CPU_SUBTYPE_SH7763) + reserve = SH7763_SKB_ALIGN + - ((uint32_t)skb->data & (SH7763_SKB_ALIGN-1)); + if (reserve) + skb_reserve(skb, reserve); +#else skb_reserve(skb, RX_OFFSET); +#endif + skb->ip_summed = CHECKSUM_NONE; rxdesc->addr = (u32)skb->data & ~0x3UL; } - /* The size of the buffer is 16 byte boundary. */ - rxdesc->buffer_length = (mdp->rx_buf_sz + 16) & ~0x0F; if (entry >= RX_RING_SIZE - 1) rxdesc->status |= - cpu_to_le32(RD_RACT | RD_RFP | RC_RDEL); + cpu_to_le32(RD_RACT | RD_RFP | RD_RDEL); else rxdesc->status |= - cpu_to_le32(RD_RACT | RD_RFP); + cpu_to_le32(RD_RACT | RD_RFP); } /* Restart Rx engine if stopped. */ /* If we don't need to check status, don't. -KDU */ - ctrl_outl(EDRRR_R, ndev->base_addr + EDRRR); + if (!(ctrl_inl(ndev->base_addr + EDRRR) & EDRRR_R)) + ctrl_outl(EDRRR_R, ndev->base_addr + EDRRR); return 0; } @@ -529,13 +615,14 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) printk(KERN_ERR "Receive Frame Overflow\n"); } } - +#if !defined(CONFIG_CPU_SUBTYPE_SH7763) if (intr_status & EESR_ADE) { if (intr_status & EESR_TDE) { if (intr_status & EESR_TFE) mdp->stats.tx_fifo_errors++; } } +#endif if (intr_status & EESR_RDE) { /* Receive Descriptor Empty int */ @@ -550,8 +637,11 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) mdp->stats.rx_fifo_errors++; printk(KERN_ERR "Receive FIFO Overflow\n"); } - if (intr_status & - (EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE)) { + if (intr_status & (EESR_TWB | EESR_TABT | +#if !defined(CONFIG_CPU_SUBTYPE_SH7763) + EESR_ADE | +#endif + EESR_TDE | EESR_TFE)) { /* Tx error */ u32 edtrr = ctrl_inl(ndev->base_addr + EDTRR); /* dmesg */ @@ -582,17 +672,23 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) ioaddr = ndev->base_addr; spin_lock(&mdp->lock); + /* Get interrpt stat */ intr_status = ctrl_inl(ioaddr + EESR); /* Clear interrupt */ ctrl_outl(intr_status, ioaddr + EESR); - if (intr_status & (EESR_FRC | EESR_RINT8 | - EESR_RINT5 | EESR_RINT4 | EESR_RINT3 | EESR_RINT2 | - EESR_RINT1)) + if (intr_status & (EESR_FRC | /* Frame recv*/ + EESR_RMAF | /* Multi cast address recv*/ + EESR_RRF | /* Bit frame recv */ + EESR_RTLF | /* Long frame recv*/ + EESR_RTSF | /* short frame recv */ + EESR_PRE | /* PHY-LSI recv error */ + EESR_CERF)){ /* recv frame CRC error */ sh_eth_rx(ndev); - if (intr_status & (EESR_FTC | - EESR_TINT4 | EESR_TINT3 | EESR_TINT2 | EESR_TINT1)) { + } + /* Tx Check */ + if (intr_status & TX_CHECK) { sh_eth_txfree(ndev); netif_wake_queue(ndev); } @@ -631,11 +727,32 @@ static void sh_eth_adjust_link(struct net_device *ndev) if (phydev->duplex != mdp->duplex) { new_state = 1; mdp->duplex = phydev->duplex; +#if defined(CONFIG_CPU_SUBTYPE_SH7763) + if (mdp->duplex) { /* FULL */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM, + ioaddr + ECMR); + } else { /* Half */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM, + ioaddr + ECMR); + } +#endif } if (phydev->speed != mdp->speed) { new_state = 1; mdp->speed = phydev->speed; +#if defined(CONFIG_CPU_SUBTYPE_SH7763) + switch (mdp->speed) { + case 10: /* 10BASE */ + ctrl_outl(GECMR_10, ioaddr + GECMR); break; + case 100:/* 100BASE */ + ctrl_outl(GECMR_100, ioaddr + GECMR); break; + case 1000: /* 1000BASE */ + ctrl_outl(GECMR_1000, ioaddr + GECMR); break; + default: + break; + } +#endif } if (mdp->link == PHY_DOWN) { ctrl_outl((ctrl_inl(ioaddr + ECMR) & ~ECMR_TXF) @@ -730,7 +847,7 @@ static int sh_eth_open(struct net_device *ndev) /* Set the timer to check for link beat. */ init_timer(&mdp->timer); mdp->timer.expires = (jiffies + (24 * HZ)) / 10;/* 2.4 sec. */ - setup_timer(&mdp->timer, sh_eth_timer, ndev); + setup_timer(&mdp->timer, sh_eth_timer, (unsigned long)ndev); return ret; @@ -820,7 +937,9 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) mdp->cur_tx++; - ctrl_outl(EDTRR_TRNS, ndev->base_addr + EDTRR); + if (!(ctrl_inl(ndev->base_addr + EDTRR) & EDTRR_TRNS)) + ctrl_outl(EDTRR_TRNS, ndev->base_addr + EDTRR); + ndev->trans_start = jiffies; return 0; @@ -877,9 +996,15 @@ static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev) ctrl_outl(0, ioaddr + CDCR); /* (write clear) */ mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + LCCR); ctrl_outl(0, ioaddr + LCCR); /* (write clear) */ +#if defined(CONFIG_CPU_SUBTYPE_SH7763) + mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CERCR);/* CERCR */ + ctrl_outl(0, ioaddr + CERCR); /* (write clear) */ + mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CEECR);/* CEECR */ + ctrl_outl(0, ioaddr + CEECR); /* (write clear) */ +#else mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CNDCR); ctrl_outl(0, ioaddr + CNDCR); /* (write clear) */ - +#endif return &mdp->stats; } @@ -929,8 +1054,13 @@ static void sh_eth_tsu_init(u32 ioaddr) ctrl_outl(0, ioaddr + TSU_FWSL0); ctrl_outl(0, ioaddr + TSU_FWSL1); ctrl_outl(TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL, ioaddr + TSU_FWSLC); +#if defined(CONFIG_CPU_SUBTYPE_SH7763) + ctrl_outl(0, ioaddr + TSU_QTAG0); /* Disable QTAG(0->1) */ + ctrl_outl(0, ioaddr + TSU_QTAG1); /* Disable QTAG(1->0) */ +#else ctrl_outl(0, ioaddr + TSU_QTAGM0); /* Disable QTAG(0->1) */ ctrl_outl(0, ioaddr + TSU_QTAGM1); /* Disable QTAG(1->0) */ +#endif ctrl_outl(0, ioaddr + TSU_FWSR); /* all interrupt status clear */ ctrl_outl(0, ioaddr + TSU_FWINMK); /* Disable all interrupt */ ctrl_outl(0, ioaddr + TSU_TEN); /* Disable all CAM entry */ @@ -1088,7 +1218,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev) /* First device only init */ if (!devno) { /* reset device */ - ctrl_outl(ARSTR_ARSTR, ndev->base_addr + ARSTR); + ctrl_outl(ARSTR_ARSTR, ARSTR); mdelay(1); /* TSU init (Init only)*/ @@ -1110,8 +1240,8 @@ static int sh_eth_drv_probe(struct platform_device *pdev) ndev->name, CARDNAME, (u32) ndev->base_addr); for (i = 0; i < 5; i++) - printk(KERN_INFO "%2.2x:", ndev->dev_addr[i]); - printk(KERN_INFO "%2.2x, IRQ %d.\n", ndev->dev_addr[i], ndev->irq); + printk(KERN_INFO "%02X:", ndev->dev_addr[i]); + printk(KERN_INFO "%02X, IRQ %d.\n", ndev->dev_addr[i], ndev->irq); platform_set_drvdata(pdev, ndev); diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h index e01e1c34771..45ad1b09ca5 100644 --- a/drivers/net/sh_eth.h +++ b/drivers/net/sh_eth.h @@ -32,118 +32,249 @@ #define CARDNAME "sh-eth" #define TX_TIMEOUT (5*HZ) - -#define TX_RING_SIZE 128 /* Tx ring size */ -#define RX_RING_SIZE 128 /* Rx ring size */ -#define RX_OFFSET 2 /* skb offset */ +#define TX_RING_SIZE 64 /* Tx ring size */ +#define RX_RING_SIZE 64 /* Rx ring size */ #define ETHERSMALL 60 #define PKT_BUF_SZ 1538 +#ifdef CONFIG_CPU_SUBTYPE_SH7763 + +#define SH7763_SKB_ALIGN 32 /* Chip Base Address */ -#define SH_TSU_ADDR 0xA7000804 +# define SH_TSU_ADDR 0xFFE01800 +# define ARSTR 0xFFE01800 + +/* Chip Registers */ +/* E-DMAC */ +# define EDSR 0x000 +# define EDMR 0x400 +# define EDTRR 0x408 +# define EDRRR 0x410 +# define EESR 0x428 +# define EESIPR 0x430 +# define TDLAR 0x010 +# define TDFAR 0x014 +# define TDFXR 0x018 +# define TDFFR 0x01C +# define RDLAR 0x030 +# define RDFAR 0x034 +# define RDFXR 0x038 +# define RDFFR 0x03C +# define TRSCER 0x438 +# define RMFCR 0x440 +# define TFTR 0x448 +# define FDR 0x450 +# define RMCR 0x458 +# define RPADIR 0x460 +# define FCFTR 0x468 + +/* Ether Register */ +# define ECMR 0x500 +# define ECSR 0x510 +# define ECSIPR 0x518 +# define PIR 0x520 +# define PSR 0x528 +# define PIPR 0x52C +# define RFLR 0x508 +# define APR 0x554 +# define MPR 0x558 +# define PFTCR 0x55C +# define PFRCR 0x560 +# define TPAUSER 0x564 +# define GECMR 0x5B0 +# define BCULR 0x5B4 +# define MAHR 0x5C0 +# define MALR 0x5C8 +# define TROCR 0x700 +# define CDCR 0x708 +# define LCCR 0x710 +# define CEFCR 0x740 +# define FRECR 0x748 +# define TSFRCR 0x750 +# define TLFRCR 0x758 +# define RFCR 0x760 +# define CERCR 0x768 +# define CEECR 0x770 +# define MAFCR 0x778 + +/* TSU Absolute Address */ +# define TSU_CTRST 0x004 +# define TSU_FWEN0 0x010 +# define TSU_FWEN1 0x014 +# define TSU_FCM 0x18 +# define TSU_BSYSL0 0x20 +# define TSU_BSYSL1 0x24 +# define TSU_PRISL0 0x28 +# define TSU_PRISL1 0x2C +# define TSU_FWSL0 0x30 +# define TSU_FWSL1 0x34 +# define TSU_FWSLC 0x38 +# define TSU_QTAG0 0x40 +# define TSU_QTAG1 0x44 +# define TSU_FWSR 0x50 +# define TSU_FWINMK 0x54 +# define TSU_ADQT0 0x48 +# define TSU_ADQT1 0x4C +# define TSU_VTAG0 0x58 +# define TSU_VTAG1 0x5C +# define TSU_ADSBSY 0x60 +# define TSU_TEN 0x64 +# define TSU_POST1 0x70 +# define TSU_POST2 0x74 +# define TSU_POST3 0x78 +# define TSU_POST4 0x7C +# define TSU_ADRH0 0x100 +# define TSU_ADRL0 0x104 +# define TSU_ADRH31 0x1F8 +# define TSU_ADRL31 0x1FC + +# define TXNLCR0 0x80 +# define TXALCR0 0x84 +# define RXNLCR0 0x88 +# define RXALCR0 0x8C +# define FWNLCR0 0x90 +# define FWALCR0 0x94 +# define TXNLCR1 0xA0 +# define TXALCR1 0xA4 +# define RXNLCR1 0xA8 +# define RXALCR1 0xAC +# define FWNLCR1 0xB0 +# define FWALCR1 0x40 + +#else /* CONFIG_CPU_SUBTYPE_SH7763 */ +# define RX_OFFSET 2 /* skb offset */ +/* Chip base address */ +# define SH_TSU_ADDR 0xA7000804 +# define ARSTR 0xA7000800 /* Chip Registers */ /* E-DMAC */ -#define EDMR 0x0000 -#define EDTRR 0x0004 -#define EDRRR 0x0008 -#define TDLAR 0x000C -#define RDLAR 0x0010 -#define EESR 0x0014 -#define EESIPR 0x0018 -#define TRSCER 0x001C -#define RMFCR 0x0020 -#define TFTR 0x0024 -#define FDR 0x0028 -#define RMCR 0x002C -#define EDOCR 0x0030 -#define FCFTR 0x0034 -#define RPADIR 0x0038 -#define TRIMD 0x003C -#define RBWAR 0x0040 -#define RDFAR 0x0044 -#define TBRAR 0x004C -#define TDFAR 0x0050 +# define EDMR 0x0000 +# define EDTRR 0x0004 +# define EDRRR 0x0008 +# define TDLAR 0x000C +# define RDLAR 0x0010 +# define EESR 0x0014 +# define EESIPR 0x0018 +# define TRSCER 0x001C +# define RMFCR 0x0020 +# define TFTR 0x0024 +# define FDR 0x0028 +# define RMCR 0x002C +# define EDOCR 0x0030 +# define FCFTR 0x0034 +# define RPADIR 0x0038 +# define TRIMD 0x003C +# define RBWAR 0x0040 +# define RDFAR 0x0044 +# define TBRAR 0x004C +# define TDFAR 0x0050 + /* Ether Register */ -#define ECMR 0x0160 -#define ECSR 0x0164 -#define ECSIPR 0x0168 -#define PIR 0x016C -#define MAHR 0x0170 -#define MALR 0x0174 -#define RFLR 0x0178 -#define PSR 0x017C -#define TROCR 0x0180 -#define CDCR 0x0184 -#define LCCR 0x0188 -#define CNDCR 0x018C -#define CEFCR 0x0194 -#define FRECR 0x0198 -#define TSFRCR 0x019C -#define TLFRCR 0x01A0 -#define RFCR 0x01A4 -#define MAFCR 0x01A8 -#define IPGR 0x01B4 -#if defined(CONFIG_CPU_SUBTYPE_SH7710) -#define APR 0x01B8 -#define MPR 0x01BC -#define TPAUSER 0x1C4 -#define BCFR 0x1CC -#endif /* CONFIG_CPU_SH7710 */ - -#define ARSTR 0x0800 +# define ECMR 0x0160 +# define ECSR 0x0164 +# define ECSIPR 0x0168 +# define PIR 0x016C +# define MAHR 0x0170 +# define MALR 0x0174 +# define RFLR 0x0178 +# define PSR 0x017C +# define TROCR 0x0180 +# define CDCR 0x0184 +# define LCCR 0x0188 +# define CNDCR 0x018C +# define CEFCR 0x0194 +# define FRECR 0x0198 +# define TSFRCR 0x019C +# define TLFRCR 0x01A0 +# define RFCR 0x01A4 +# define MAFCR 0x01A8 +# define IPGR 0x01B4 +# if defined(CONFIG_CPU_SUBTYPE_SH7710) +# define APR 0x01B8 +# define MPR 0x01BC +# define TPAUSER 0x1C4 +# define BCFR 0x1CC +# endif /* CONFIG_CPU_SH7710 */ /* TSU */ -#define TSU_CTRST 0x004 -#define TSU_FWEN0 0x010 -#define TSU_FWEN1 0x014 -#define TSU_FCM 0x018 -#define TSU_BSYSL0 0x020 -#define TSU_BSYSL1 0x024 -#define TSU_PRISL0 0x028 -#define TSU_PRISL1 0x02C -#define TSU_FWSL0 0x030 -#define TSU_FWSL1 0x034 -#define TSU_FWSLC 0x038 -#define TSU_QTAGM0 0x040 -#define TSU_QTAGM1 0x044 -#define TSU_ADQT0 0x048 -#define TSU_ADQT1 0x04C -#define TSU_FWSR 0x050 -#define TSU_FWINMK 0x054 -#define TSU_ADSBSY 0x060 -#define TSU_TEN 0x064 -#define TSU_POST1 0x070 -#define TSU_POST2 0x074 -#define TSU_POST3 0x078 -#define TSU_POST4 0x07C -#define TXNLCR0 0x080 -#define TXALCR0 0x084 -#define RXNLCR0 0x088 -#define RXALCR0 0x08C -#define FWNLCR0 0x090 -#define FWALCR0 0x094 -#define TXNLCR1 0x0A0 -#define TXALCR1 0x0A4 -#define RXNLCR1 0x0A8 -#define RXALCR1 0x0AC -#define FWNLCR1 0x0B0 -#define FWALCR1 0x0B4 +# define TSU_CTRST 0x004 +# define TSU_FWEN0 0x010 +# define TSU_FWEN1 0x014 +# define TSU_FCM 0x018 +# define TSU_BSYSL0 0x020 +# define TSU_BSYSL1 0x024 +# define TSU_PRISL0 0x028 +# define TSU_PRISL1 0x02C +# define TSU_FWSL0 0x030 +# define TSU_FWSL1 0x034 +# define TSU_FWSLC 0x038 +# define TSU_QTAGM0 0x040 +# define TSU_QTAGM1 0x044 +# define TSU_ADQT0 0x048 +# define TSU_ADQT1 0x04C +# define TSU_FWSR 0x050 +# define TSU_FWINMK 0x054 +# define TSU_ADSBSY 0x060 +# define TSU_TEN 0x064 +# define TSU_POST1 0x070 +# define TSU_POST2 0x074 +# define TSU_POST3 0x078 +# define TSU_POST4 0x07C +# define TXNLCR0 0x080 +# define TXALCR0 0x084 +# define RXNLCR0 0x088 +# define RXALCR0 0x08C +# define FWNLCR0 0x090 +# define FWALCR0 0x094 +# define TXNLCR1 0x0A0 +# define TXALCR1 0x0A4 +# define RXNLCR1 0x0A8 +# define RXALCR1 0x0AC +# define FWNLCR1 0x0B0 +# define FWALCR1 0x0B4 #define TSU_ADRH0 0x0100 #define TSU_ADRL0 0x0104 #define TSU_ADRL31 0x01FC -/* Register's bits */ +#endif /* CONFIG_CPU_SUBTYPE_SH7763 */ + +/* + * Register's bits + */ +#ifdef CONFIG_CPU_SUBTYPE_SH7763 +/* EDSR */ +enum EDSR_BIT { + EDSR_ENT = 0x01, EDSR_ENR = 0x02, +}; +#define EDSR_ENALL (EDSR_ENT|EDSR_ENR) + +/* GECMR */ +enum GECMR_BIT { + GECMR_10 = 0x0, GECMR_100 = 0x04, GECMR_1000 = 0x01, +}; +#endif /* EDMR */ enum DMAC_M_BIT { - EDMR_DL1 = 0x20, EDMR_DL0 = 0x10, EDMR_SRST = 0x01, + EDMR_DL1 = 0x20, EDMR_DL0 = 0x10, +#ifdef CONFIG_CPU_SUBTYPE_SH7763 + EDMR_SRST = 0x03, + EMDR_DESC_R = 0x30, /* Descriptor reserve size */ + EDMR_EL = 0x40, /* Litte endian */ +#else /* CONFIG_CPU_SUBTYPE_SH7763 */ + EDMR_SRST = 0x01, +#endif }; /* EDTRR */ enum DMAC_T_BIT { +#ifdef CONFIG_CPU_SUBTYPE_SH7763 + EDTRR_TRNS = 0x03, +#else EDTRR_TRNS = 0x01, +#endif }; /* EDRRR*/ @@ -173,21 +304,47 @@ enum PHY_STATUS_BIT { PHY_ST_LINK = 0x01, }; /* EESR */ enum EESR_BIT { - EESR_TWB = 0x40000000, EESR_TABT = 0x04000000, +#ifndef CONFIG_CPU_SUBTYPE_SH7763 + EESR_TWB = 0x40000000, +#else + EESR_TWB = 0xC0000000, + EESR_TC1 = 0x20000000, + EESR_TUC = 0x10000000, + EESR_ROC = 0x80000000, +#endif + EESR_TABT = 0x04000000, EESR_RABT = 0x02000000, EESR_RFRMER = 0x01000000, - EESR_ADE = 0x00800000, EESR_ECI = 0x00400000, - EESR_FTC = 0x00200000, EESR_TDE = 0x00100000, - EESR_TFE = 0x00080000, EESR_FRC = 0x00040000, - EESR_RDE = 0x00020000, EESR_RFE = 0x00010000, - EESR_TINT4 = 0x00000800, EESR_TINT3 = 0x00000400, - EESR_TINT2 = 0x00000200, EESR_TINT1 = 0x00000100, - EESR_RINT8 = 0x00000080, EESR_RINT5 = 0x00000010, - EESR_RINT4 = 0x00000008, EESR_RINT3 = 0x00000004, - EESR_RINT2 = 0x00000002, EESR_RINT1 = 0x00000001, -}; - -#define EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \ +#ifndef CONFIG_CPU_SUBTYPE_SH7763 + EESR_ADE = 0x00800000, +#endif + EESR_ECI = 0x00400000, + EESR_FTC = 0x00200000, EESR_TDE = 0x00100000, + EESR_TFE = 0x00080000, EESR_FRC = 0x00040000, + EESR_RDE = 0x00020000, EESR_RFE = 0x00010000, +#ifndef CONFIG_CPU_SUBTYPE_SH7763 + EESR_CND = 0x00000800, +#endif + EESR_DLC = 0x00000400, + EESR_CD = 0x00000200, EESR_RTO = 0x00000100, + EESR_RMAF = 0x00000080, EESR_CEEF = 0x00000040, + EESR_CELF = 0x00000020, EESR_RRF = 0x00000010, + EESR_RTLF = 0x00000008, EESR_RTSF = 0x00000004, + EESR_PRE = 0x00000002, EESR_CERF = 0x00000001, +}; + + +#ifdef CONFIG_CPU_SUBTYPE_SH7763 +# define TX_CHECK (EESR_TC1 | EESR_FTC) +# define EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \ + | EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI) +# define TX_ERROR_CEHCK (EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE) + +#else +# define TX_CHECK (EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO) +# define EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \ | EESR_RFRMER | EESR_ADE | EESR_TFE | EESR_TDE | EESR_ECI) +# define TX_ERROR_CEHCK (EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE) +#endif /* EESIPR */ enum DMAC_IM_BIT { @@ -207,8 +364,8 @@ enum DMAC_IM_BIT { /* Receive descriptor bit */ enum RD_STS_BIT { - RD_RACT = 0x80000000, RC_RDEL = 0x40000000, - RC_RFP1 = 0x20000000, RC_RFP0 = 0x10000000, + RD_RACT = 0x80000000, RD_RDEL = 0x40000000, + RD_RFP1 = 0x20000000, RD_RFP0 = 0x10000000, RD_RFE = 0x08000000, RD_RFS10 = 0x00000200, RD_RFS9 = 0x00000100, RD_RFS8 = 0x00000080, RD_RFS7 = 0x00000040, RD_RFS6 = 0x00000020, @@ -216,9 +373,9 @@ enum RD_STS_BIT { RD_RFS3 = 0x00000004, RD_RFS2 = 0x00000002, RD_RFS1 = 0x00000001, }; -#define RDF1ST RC_RFP1 -#define RDFEND RC_RFP0 -#define RD_RFP (RC_RFP1|RC_RFP0) +#define RDF1ST RD_RFP1 +#define RDFEND RD_RFP0 +#define RD_RFP (RD_RFP1|RD_RFP0) /* FCFTR */ enum FCFTR_BIT { @@ -231,7 +388,8 @@ enum FCFTR_BIT { /* Transfer descriptor bit */ enum TD_STS_BIT { - TD_TACT = 0x80000000, TD_TDLE = 0x40000000, TD_TFP1 = 0x20000000, + TD_TACT = 0x80000000, + TD_TDLE = 0x40000000, TD_TFP1 = 0x20000000, TD_TFP0 = 0x10000000, }; #define TDF1ST TD_TFP1 @@ -242,6 +400,10 @@ enum TD_STS_BIT { enum RECV_RST_BIT { RMCR_RST = 0x01, }; /* ECMR */ enum FELIC_MODE_BIT { +#ifdef CONFIG_CPU_SUBTYPE_SH7763 + ECMR_TRCCM = 0x04000000, ECMR_RCSC = 0x00800000, + ECMR_DPAD = 0x00200000, ECMR_RZPF = 0x00100000, +#endif ECMR_ZPF = 0x00080000, ECMR_PFR = 0x00040000, ECMR_RXF = 0x00020000, ECMR_TXF = 0x00010000, ECMR_MCT = 0x00002000, ECMR_PRCEF = 0x00001000, ECMR_PMDE = 0x00000200, ECMR_RE = 0x00000040, ECMR_TE = 0x00000020, @@ -249,18 +411,45 @@ enum FELIC_MODE_BIT { ECMR_PRM = 0x00000001, }; +#ifdef CONFIG_CPU_SUBTYPE_SH7763 +#define ECMR_CHG_DM (ECMR_TRCCM | ECMR_RZPF | ECMR_ZPF |\ + ECMR_PFR | ECMR_RXF | ECMR_TXF | ECMR_MCT) +#else +#define ECMR_CHG_DM (ECMR_ZPF | ECMR_PFR ECMR_RXF | ECMR_TXF | ECMR_MCT) +#endif + /* ECSR */ enum ECSR_STATUS_BIT { - ECSR_BRCRX = 0x20, ECSR_PSRTO = 0x10, ECSR_LCHNG = 0x04, +#ifndef CONFIG_CPU_SUBTYPE_SH7763 + ECSR_BRCRX = 0x20, ECSR_PSRTO = 0x10, +#endif + ECSR_LCHNG = 0x04, ECSR_MPD = 0x02, ECSR_ICD = 0x01, }; +#ifdef CONFIG_CPU_SUBTYPE_SH7763 +# define ECSR_INIT (ECSR_ICD | ECSIPR_MPDIP) +#else +# define ECSR_INIT (ECSR_BRCRX | ECSR_PSRTO | \ + ECSR_LCHNG | ECSR_ICD | ECSIPR_MPDIP) +#endif + /* ECSIPR */ enum ECSIPR_STATUS_MASK_BIT { - ECSIPR_BRCRXIP = 0x20, ECSIPR_PSRTOIP = 0x10, ECSIPR_LCHNGIP = 0x04, +#ifndef CONFIG_CPU_SUBTYPE_SH7763 + ECSIPR_BRCRXIP = 0x20, ECSIPR_PSRTOIP = 0x10, +#endif + ECSIPR_LCHNGIP = 0x04, ECSIPR_MPDIP = 0x02, ECSIPR_ICDIP = 0x01, }; +#ifdef CONFIG_CPU_SUBTYPE_SH7763 +# define ECSIPR_INIT (ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP) +#else +# define ECSIPR_INIT (ECSIPR_BRCRXIP | ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | \ + ECSIPR_ICDIP | ECSIPR_MPDIP) +#endif + /* APR */ enum APR_BIT { APR_AP = 0x00000001, @@ -285,6 +474,15 @@ enum RPADIR_BIT { RPADIR_PADR = 0x0003f, }; +#if defined(CONFIG_CPU_SUBTYPE_SH7763) +# define RPADIR_INIT (0x00) +#else +# define RPADIR_INIT (RPADIR_PADS1) +#endif + +/* RFLR */ +#define RFLR_VALUE 0x1000 + /* FDR */ enum FIFO_SIZE_BIT { FIFO_SIZE_T = 0x00000700, FIFO_SIZE_R = 0x00000007, @@ -316,7 +514,7 @@ enum PHY_ANA_BIT { PHY_A_NP = 0x8000, PHY_A_ACK = 0x4000, PHY_A_RF = 0x2000, PHY_A_FCS = 0x0400, PHY_A_T4 = 0x0200, PHY_A_FDX = 0x0100, PHY_A_HDX = 0x0080, PHY_A_10FDX = 0x0040, PHY_A_10HDX = 0x0020, - PHY_A_SEL = 0x001f, + PHY_A_SEL = 0x001e, }; /* PHY_ANL */ enum PHY_ANL_BIT { @@ -449,6 +647,10 @@ struct sh_eth_private { struct net_device_stats tsu_stats; /* TSU forward status */ }; +#ifdef CONFIG_CPU_SUBTYPE_SH7763 +/* SH7763 has endian control register */ +#define swaps(x, y) +#else static void swaps(char *src, int len) { #ifdef __LITTLE_ENDIAN__ @@ -460,5 +662,5 @@ static void swaps(char *src, int len) *p = swab32(*p); #endif } - +#endif /* CONFIG_CPU_SUBTYPE_SH7763 */ #endif -- cgit v1.2.3 From 68905eb4dc9c691ba09df767ac0641395025cef6 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 21 Jul 2008 09:57:26 +0200 Subject: drivers/net/ehea/ehea_main.c: Release mutex in error handling code The mutex is released on a successful return, so it would seem that it should be released on an error return as well. The semantic patch finds this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ expression l; @@ mutex_lock(l); ... when != mutex_unlock(l) when any when strict ( if (...) { ... when != mutex_unlock(l) + mutex_unlock(l); return ...; } | mutex_unlock(l); ) // Signed-off-by: Julia Lawall Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 0920b796bd7..b70c5314f53 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -2937,9 +2937,9 @@ static void ehea_rereg_mrs(struct work_struct *work) } } } - mutex_unlock(&dlpar_mem_lock); - ehea_info("re-initializing driver complete"); + ehea_info("re-initializing driver complete"); out: + mutex_unlock(&dlpar_mem_lock); return; } -- cgit v1.2.3 From 6a8341b68b5269de71c32c6df91f4b0298da031d Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Wed, 30 Jul 2008 16:30:15 -0700 Subject: net: use the common ascii hex helpers Signed-off-by: Harvey Harrison Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/skfp/smt.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c index ffbfb1b79f9..805383b33d3 100644 --- a/drivers/net/skfp/smt.c +++ b/drivers/net/skfp/smt.c @@ -19,6 +19,7 @@ #include "h/smc.h" #include "h/smt_p.h" #include +#include #define KERNEL #include "h/smtstate.h" @@ -1730,20 +1731,18 @@ void fddi_send_antc(struct s_smc *smc, struct fddi_addr *dest) #endif #ifdef DEBUG -#define hextoasc(x) "0123456789abcdef"[x] - char *addr_to_string(struct fddi_addr *addr) { int i ; static char string[6*3] = "****" ; for (i = 0 ; i < 6 ; i++) { - string[i*3] = hextoasc((addr->a[i]>>4)&0xf) ; - string[i*3+1] = hextoasc((addr->a[i])&0xf) ; - string[i*3+2] = ':' ; + string[i * 3] = hex_asc_hi(addr->a[i]); + string[i * 3 + 1] = hex_asc_lo(addr->a[i]); + string[i * 3 + 2] = ':'; } - string[5*3+2] = 0 ; - return(string) ; + string[5 * 3 + 2] = 0; + return(string); } #endif -- cgit v1.2.3 From 849e8caa477d72cf153e5c0b6ce0c00b89738abb Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 30 Jul 2008 16:33:05 -0700 Subject: atm: fix direct casts of pointers to u32 in the InterPhase driver Fix direct casts of pointers to u32 in the InterPhase ATM driver. These are all arguments being passed to printk() calls. So drop the cast and change the %x to a %p. Signed-off-by: David Howells Acked-by: Chas Williams Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/atm/iphase.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 24df73ad326..088885ed51b 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -156,8 +156,8 @@ static void ia_hack_tcq(IADEV *dev) { } iavcc_r->vc_desc_cnt--; dev->desc_tbl[desc1 -1].timestamp = 0; - IF_EVENT(printk("ia_hack: return_q skb = 0x%x desc = %d\n", - (u32)dev->desc_tbl[desc1 -1].txskb, desc1);) + IF_EVENT(printk("ia_hack: return_q skb = 0x%p desc = %d\n", + dev->desc_tbl[desc1 -1].txskb, desc1);) if (iavcc_r->pcr < dev->rate_limit) { IA_SKB_STATE (dev->desc_tbl[desc1-1].txskb) |= IA_TX_DONE; if (ia_enque_rtn_q(&dev->tx_return_q, dev->desc_tbl[desc1 -1]) < 0) @@ -527,8 +527,8 @@ static int ia_cbr_setup (IADEV *dev, struct atm_vcc *vcc) { inc = 0; testSlot = idealSlot; TstSchedTbl = (u16*)(SchedTbl+testSlot); //set index and read in value - IF_CBR(printk("CBR Testslot 0x%x AT Location 0x%x, NumToAssign=%d\n", - testSlot, (u32)TstSchedTbl,toBeAssigned);) + IF_CBR(printk("CBR Testslot 0x%x AT Location 0x%p, NumToAssign=%d\n", + testSlot, TstSchedTbl,toBeAssigned);) memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(cbrVC)); while (cbrVC) // If another VC at this location, we have to keep looking { @@ -536,8 +536,8 @@ static int ia_cbr_setup (IADEV *dev, struct atm_vcc *vcc) { testSlot = idealSlot - inc; if (testSlot < 0) { // Wrap if necessary testSlot += dev->CbrTotEntries; - IF_CBR(printk("Testslot Wrap. STable Start=0x%x,Testslot=%d\n", - (u32)SchedTbl,testSlot);) + IF_CBR(printk("Testslot Wrap. STable Start=0x%p,Testslot=%d\n", + SchedTbl,testSlot);) } TstSchedTbl = (u16 *)(SchedTbl + testSlot); // set table index memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(cbrVC)); @@ -552,8 +552,8 @@ static int ia_cbr_setup (IADEV *dev, struct atm_vcc *vcc) { } // set table index and read in value TstSchedTbl = (u16*)(SchedTbl + testSlot); - IF_CBR(printk("Reading CBR Tbl from 0x%x, CbrVal=0x%x Iteration %d\n", - (u32)TstSchedTbl,cbrVC,inc);) + IF_CBR(printk("Reading CBR Tbl from 0x%p, CbrVal=0x%x Iteration %d\n", + TstSchedTbl,cbrVC,inc);) memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(cbrVC)); } /* while */ // Move this VCI number into this location of the CBR Sched table. @@ -1427,11 +1427,11 @@ static int rx_init(struct atm_dev *dev) /* We know this is 32bit bus addressed so the following is safe */ writel(iadev->rx_dle_dma & 0xfffff000, iadev->dma + IPHASE5575_RX_LIST_ADDR); - IF_INIT(printk("Tx Dle list addr: 0x%08x value: 0x%0x\n", - (u32)(iadev->dma+IPHASE5575_TX_LIST_ADDR), + IF_INIT(printk("Tx Dle list addr: 0x%p value: 0x%0x\n", + iadev->dma+IPHASE5575_TX_LIST_ADDR, *(u32*)(iadev->dma+IPHASE5575_TX_LIST_ADDR)); - printk("Rx Dle list addr: 0x%08x value: 0x%0x\n", - (u32)(iadev->dma+IPHASE5575_RX_LIST_ADDR), + printk("Rx Dle list addr: 0x%p value: 0x%0x\n", + iadev->dma+IPHASE5575_RX_LIST_ADDR, *(u32*)(iadev->dma+IPHASE5575_RX_LIST_ADDR));) writew(0xffff, iadev->reass_reg+REASS_MASK_REG); @@ -1470,7 +1470,7 @@ static int rx_init(struct atm_dev *dev) buf_desc_ptr++; rx_pkt_start += iadev->rx_buf_sz; } - IF_INIT(printk("Rx Buffer desc ptr: 0x%0x\n", (u32)(buf_desc_ptr));) + IF_INIT(printk("Rx Buffer desc ptr: 0x%p\n", buf_desc_ptr);) i = FREE_BUF_DESC_Q*iadev->memSize; writew(i >> 16, iadev->reass_reg+REASS_QUEUE_BASE); writew(i, iadev->reass_reg+FREEQ_ST_ADR); @@ -1487,7 +1487,7 @@ static int rx_init(struct atm_dev *dev) *freeq_start = (u_short)i; freeq_start++; } - IF_INIT(printk("freeq_start: 0x%0x\n", (u32)freeq_start);) + IF_INIT(printk("freeq_start: 0x%p\n", freeq_start);) /* Packet Complete Queue */ i = (PKT_COMP_Q * iadev->memSize) & 0xffff; writew(i, iadev->reass_reg+PCQ_ST_ADR); @@ -1713,7 +1713,7 @@ static void tx_dle_intr(struct atm_dev *dev) IA_SKB_STATE(skb) |= IA_DLED; skb_queue_tail(&iavcc->txing_skb, skb); } - IF_EVENT(printk("tx_dle_intr: enque skb = 0x%x \n", (u32)skb);) + IF_EVENT(printk("tx_dle_intr: enque skb = 0x%p \n", skb);) if (++dle == iadev->tx_dle_q.end) dle = iadev->tx_dle_q.start; } @@ -2044,8 +2044,8 @@ static int tx_init(struct atm_dev *dev) writew(tmp16, iadev->seg_reg+CBR_TAB_END+1); // CBR_PTR; tmp16 = (CBR_SCHED_TABLE*iadev->memSize + iadev->num_vc*6 - 2) >> 1; writew(tmp16, iadev->seg_reg+CBR_TAB_END); - IF_INIT(printk("iadev->seg_reg = 0x%x CBR_PTR_BASE = 0x%x\n", - (u32)iadev->seg_reg, readw(iadev->seg_reg+CBR_PTR_BASE));) + IF_INIT(printk("iadev->seg_reg = 0x%p CBR_PTR_BASE = 0x%x\n", + iadev->seg_reg, readw(iadev->seg_reg+CBR_PTR_BASE));) IF_INIT(printk("CBR_TAB_BEG = 0x%x, CBR_TAB_END = 0x%x, CBR_PTR = 0x%x\n", readw(iadev->seg_reg+CBR_TAB_BEG), readw(iadev->seg_reg+CBR_TAB_END), readw(iadev->seg_reg+CBR_TAB_END+1));) @@ -2963,8 +2963,8 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) { /* Put the packet in a tx buffer */ trailer = iadev->tx_buf[desc-1].cpcs; - IF_TX(printk("Sent: skb = 0x%x skb->data: 0x%x len: %d, desc: %d\n", - (u32)skb, (u32)skb->data, skb->len, desc);) + IF_TX(printk("Sent: skb = 0x%p skb->data: 0x%p len: %d, desc: %d\n", + skb, skb->data, skb->len, desc);) trailer->control = 0; /*big endian*/ trailer->length = ((skb->len & 0xff) << 8) | ((skb->len & 0xff00) >> 8); @@ -3181,7 +3181,7 @@ static int __devinit ia_init_one(struct pci_dev *pdev, } dev->dev_data = iadev; IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n", dev->number);) - IF_INIT(printk("dev_id = 0x%x iadev->LineRate = %d \n", (u32)dev, + IF_INIT(printk("dev_id = 0x%p iadev->LineRate = %d \n", dev, iadev->LineRate);) pci_set_drvdata(pdev, dev); -- cgit v1.2.3 From 12dac0756d357325b107fe6ec24921ec38661839 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 30 Jul 2008 16:37:33 -0700 Subject: tg3: adapt tg3 to use reworked PCI PM code Adapt the tg3 driver to use the reworked PCI PM and make it use the exported PCI PM core functions instead of accessing the PCI PM registers directly by itself. Signed-off-by: Rafael J. Wysocki Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/tg3.c | 67 +++++++++++++++++++++++-------------------------------- 1 file changed, 28 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 633c128a622..26aa37aa531 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1982,8 +1982,6 @@ static void tg3_power_down_phy(struct tg3 *tp) static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) { u32 misc_host_ctrl; - u16 power_control, power_caps; - int pm = tp->pm_cap; /* Make sure register accesses (indirect or otherwise) * will function correctly. @@ -1992,18 +1990,10 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl); - pci_read_config_word(tp->pdev, - pm + PCI_PM_CTRL, - &power_control); - power_control |= PCI_PM_CTRL_PME_STATUS; - power_control &= ~(PCI_PM_CTRL_STATE_MASK); switch (state) { case PCI_D0: - power_control |= 0; - pci_write_config_word(tp->pdev, - pm + PCI_PM_CTRL, - power_control); - udelay(100); /* Delay after power state change */ + pci_enable_wake(tp->pdev, state, false); + pci_set_power_state(tp->pdev, PCI_D0); /* Switch out of Vaux if it is a NIC */ if (tp->tg3_flags2 & TG3_FLG2_IS_NIC) @@ -2012,26 +2002,15 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) return 0; case PCI_D1: - power_control |= 1; - break; - case PCI_D2: - power_control |= 2; - break; - case PCI_D3hot: - power_control |= 3; break; default: - printk(KERN_WARNING PFX "%s: Invalid power state (%d) " - "requested.\n", - tp->dev->name, state); + printk(KERN_ERR PFX "%s: Invalid power state (D%d) requested\n", + tp->dev->name, state); return -EINVAL; } - - power_control |= PCI_PM_CTRL_PME_ENABLE; - misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL); tw32(TG3PCI_MISC_HOST_CTRL, misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT); @@ -2109,8 +2088,6 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) WOL_DRV_WOL | WOL_SET_MAGIC_PKT); - pci_read_config_word(tp->pdev, pm + PCI_PM_PMC, &power_caps); - if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) { u32 mac_mode; @@ -2143,8 +2120,8 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) if (!(tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) tw32(MAC_LED_CTRL, tp->led_ctrl); - if (((power_caps & PCI_PM_CAP_PME_D3cold) && - (tp->tg3_flags & TG3_FLAG_WOL_ENABLE))) + if (pci_pme_capable(tp->pdev, state) && + (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE; tw32_f(MAC_MODE, mac_mode); @@ -2236,9 +2213,11 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN); + if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) + pci_enable_wake(tp->pdev, state, true); + /* Finally, set the new power state. */ - pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control); - udelay(100); /* Delay after power state change */ + pci_set_power_state(tp->pdev, state); return 0; } @@ -9065,7 +9044,8 @@ static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct tg3 *tp = netdev_priv(dev); - if (tp->tg3_flags & TG3_FLAG_WOL_CAP) + if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) && + device_can_wakeup(&tp->pdev->dev)) wol->supported = WAKE_MAGIC; else wol->supported = 0; @@ -9078,18 +9058,22 @@ static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct tg3 *tp = netdev_priv(dev); + struct device *dp = &tp->pdev->dev; if (wol->wolopts & ~WAKE_MAGIC) return -EINVAL; if ((wol->wolopts & WAKE_MAGIC) && - !(tp->tg3_flags & TG3_FLAG_WOL_CAP)) + !((tp->tg3_flags & TG3_FLAG_WOL_CAP) && device_can_wakeup(dp))) return -EINVAL; spin_lock_bh(&tp->lock); - if (wol->wolopts & WAKE_MAGIC) + if (wol->wolopts & WAKE_MAGIC) { tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; - else + device_set_wakeup_enable(dp, true); + } else { tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE; + device_set_wakeup_enable(dp, false); + } spin_unlock_bh(&tp->lock); return 0; @@ -11296,7 +11280,8 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (val & VCPU_CFGSHDW_ASPM_DBNC) tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND; if ((val & VCPU_CFGSHDW_WOL_ENABLE) && - (val & VCPU_CFGSHDW_WOL_MAGPKT)) + (val & VCPU_CFGSHDW_WOL_MAGPKT) && + device_may_wakeup(&tp->pdev->dev)) tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; return; } @@ -11426,8 +11411,9 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) !(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)) tp->tg3_flags &= ~TG3_FLAG_WOL_CAP; - if (tp->tg3_flags & TG3_FLAG_WOL_CAP && - nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE) + if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) && + (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE) && + device_may_wakeup(&tp->pdev->dev)) tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; if (cfg2 & (1 << 17)) @@ -13613,6 +13599,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); struct tg3 *tp = netdev_priv(dev); + pci_power_t target_state; int err; /* PCI register 4 needs to be saved whether netif_running() or not. @@ -13641,7 +13628,9 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; tg3_full_unlock(tp); - err = tg3_set_power_state(tp, pci_choose_state(pdev, state)); + target_state = pdev->pm_cap ? pci_target_state(pdev) : PCI_D3hot; + + err = tg3_set_power_state(tp, target_state); if (err) { int err2; -- cgit v1.2.3 From 02137f2e80a4fb1481b2b1663d3d3795e705c5bc Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Wed, 30 Jul 2008 16:40:22 -0700 Subject: isdn: use the common ascii hex helpers Signed-off-by: Harvey Harrison Acked-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/isdn/gigaset/isocdata.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index e30a7773f93..fbce5222d83 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -247,7 +247,6 @@ static inline void dump_bytes(enum debuglevel level, const char *tag, #ifdef CONFIG_GIGASET_DEBUG unsigned char c; static char dbgline[3 * 32 + 1]; - static const char hexdigit[] = "0123456789abcdef"; int i = 0; while (count-- > 0) { if (i > sizeof(dbgline) - 4) { @@ -258,8 +257,8 @@ static inline void dump_bytes(enum debuglevel level, const char *tag, c = *bytes++; dbgline[i] = (i && !(i % 12)) ? '-' : ' '; i++; - dbgline[i++] = hexdigit[(c >> 4) & 0x0f]; - dbgline[i++] = hexdigit[c & 0x0f]; + dbgline[i++] = hex_asc_hi(c); + dbgline[i++] = hex_asc_lo(c); } dbgline[i] = '\0'; gig_dbg(level, "%s:%s", tag, dbgline); -- cgit v1.2.3 From a7403e807d5f6431a09abb13a00f8170dac1da29 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 30 Jul 2008 16:48:05 -0700 Subject: hysdn: remove the packed attribute from PofTimStamp_tag Remove the packed attribute from PofTimStamp_tag in the hysdn driver as the thing being packed is just an array of chars and so is unpackable. This deals with a compiler warning: In file included from drivers/isdn/hysdn/hysdn_boot.c:19: drivers/isdn/hysdn/hysdn_pof.h:63: warning: 'packed' attribute ignored for field of type 'unsigned char[40]' Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/isdn/hysdn/hysdn_pof.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/isdn/hysdn/hysdn_pof.h b/drivers/isdn/hysdn/hysdn_pof.h index a368d6caca0..3a72b908900 100644 --- a/drivers/isdn/hysdn/hysdn_pof.h +++ b/drivers/isdn/hysdn/hysdn_pof.h @@ -60,7 +60,7 @@ typedef struct PofRecHdr_tag { /* Pof record header */ typedef struct PofTimeStamp_tag { /*00 */ unsigned long UnixTime __attribute__((packed)); - /*04 */ unsigned char DateTimeText[0x28] __attribute__((packed)); + /*04 */ unsigned char DateTimeText[0x28]; /* =40 */ /*2C */ } tPofTimeStamp; -- cgit v1.2.3 From c9b23e0c302377ccff700bee663b878d04e4ef3a Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 30 Jul 2008 16:49:52 -0700 Subject: sparc: Ignore drivers/video/console/promcon_tbl.c conmakehash generated file Add drivers/video/console/promcon_tbl.c to the list of ignored files. This file is generated by conmakehash against drivers/video/console/prom.uni. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/video/console/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 drivers/video/console/.gitignore (limited to 'drivers') diff --git a/drivers/video/console/.gitignore b/drivers/video/console/.gitignore new file mode 100644 index 00000000000..0c258b45439 --- /dev/null +++ b/drivers/video/console/.gitignore @@ -0,0 +1,2 @@ +# conmakehash generated file +promcon_tbl.c -- cgit v1.2.3 From 5aa10cad69d282acfaf89d3c16ee07f9b279dbd2 Mon Sep 17 00:00:00 2001 From: Michael Frey Date: Wed, 30 Jul 2008 16:59:15 -0700 Subject: bluetooth: add quirks for a few hci_usb devices Preface: The "Broadcom" device is on unreleased hardware, so I can't disclose the actual model. When the Dell 370 and 410 BT adapters are put into BT radio mode, they need to be prepared like many other Broadcom adapters. Also, add quirk Broadcom 2046 devices with HCI_RESET. Reference for this bug: https://launchpad.net/bugs/249448 Signed-off-by: Michael Frey Signed-off-by: Mario Limonciello Signed-off-by: Tim Gardner Signed-off-by: Ben Collins Acked-by: Marcel Holtmann Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/bluetooth/hci_usb.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index 192522ebb77..c33bb59ed1f 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -134,6 +134,13 @@ static struct usb_device_id blacklist_ids[] = { /* Dell laptop with Broadcom chip */ { USB_DEVICE(0x413c, 0x8126), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, + /* Dell Wireless 370 */ + { USB_DEVICE(0x413c, 0x8156), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, + /* Dell Wireless 410 */ + { USB_DEVICE(0x413c, 0x8152), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, + + /* Broadcom 2046 */ + { USB_DEVICE(0x0a5c, 0x2151), .driver_info = HCI_RESET }, /* Microsoft Wireless Transceiver for Bluetooth 2.0 */ { USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET }, -- cgit v1.2.3 From 1fa98174ba980b2826edd1e4632a17916dfdb4fa Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 30 Jul 2008 17:00:38 -0700 Subject: nsc-ircc: default to dongle type 9 on IBM hardware This is necessary to set the dongle type on the nsc driver in order to get it to work correctly. Thinkpads all appear to use dongle type 9. This patch defaults nsc devices with an IBM PnP descriptor to use type 9. Signed-off-by: Matthew Garrett Signed-off-by: Ben Collins Signed-off-by: Andrew Morton --- drivers/net/irda/nsc-ircc.c | 7 +++++-- drivers/net/irda/nsc-ircc.h | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index effc1ce8179..18d17143537 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -151,8 +151,8 @@ static char *dongle_types[] = { static chipio_t pnp_info; static const struct pnp_device_id nsc_ircc_pnp_table[] = { { .id = "NSC6001", .driver_data = 0 }, - { .id = "IBM0071", .driver_data = 0 }, { .id = "HWPC224", .driver_data = 0 }, + { .id = "IBM0071", .driver_data = NSC_FORCE_DONGLE_TYPE9 }, { } }; @@ -930,7 +930,10 @@ static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *i pnp_info.dma = -1; pnp_succeeded = 1; - /* There don't seem to be any way to get the cfg_base. + if (id->driver_data & NSC_FORCE_DONGLE_TYPE9) + dongle_id = 0x9; + + /* There doesn't seem to be any way of getting the cfg_base. * On my box, cfg_base is in the PnP descriptor of the * motherboard. Oh well... Jean II */ diff --git a/drivers/net/irda/nsc-ircc.h b/drivers/net/irda/nsc-ircc.h index 29398a4f73f..71cd3c5a076 100644 --- a/drivers/net/irda/nsc-ircc.h +++ b/drivers/net/irda/nsc-ircc.h @@ -35,6 +35,9 @@ #include #include +/* Features for chips (set in driver_data) */ +#define NSC_FORCE_DONGLE_TYPE9 0x00000001 + /* DMA modes needed */ #define DMA_TX_MODE 0x08 /* Mem to I/O, ++, demand. */ #define DMA_RX_MODE 0x04 /* I/O to mem, ++, demand. */ -- cgit v1.2.3 From a97a6f10771b90235b33c13a6db9279237a08422 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Wed, 30 Jul 2008 17:20:18 -0700 Subject: irda: replace __FUNCTION__ with __func__ __FUNCTION__ is gcc-specific, use __func__ Signed-off-by: Harvey Harrison Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/irda/act200l-sir.c | 10 +- drivers/net/irda/actisys-sir.c | 2 +- drivers/net/irda/ali-ircc.c | 246 +++++++++++++++++++------------------- drivers/net/irda/donauboe.c | 68 +++++------ drivers/net/irda/girbil-sir.c | 12 +- drivers/net/irda/irda-usb.c | 92 +++++++------- drivers/net/irda/irtty-sir.c | 10 +- drivers/net/irda/kingsun-sir.c | 2 +- drivers/net/irda/litelink-sir.c | 8 +- drivers/net/irda/ma600-sir.c | 16 +-- drivers/net/irda/mcp2120-sir.c | 12 +- drivers/net/irda/nsc-ircc.c | 112 ++++++++--------- drivers/net/irda/old_belkin-sir.c | 8 +- drivers/net/irda/sir_dev.c | 63 +++++----- drivers/net/irda/sir_dongle.c | 2 +- drivers/net/irda/smsc-ircc2.c | 120 +++++++++---------- drivers/net/irda/tekram-sir.c | 10 +- drivers/net/irda/toim3232-sir.c | 10 +- drivers/net/irda/via-ircc.c | 80 ++++++------- drivers/net/irda/vlsi_ir.c | 92 +++++++------- drivers/net/irda/vlsi_ir.h | 2 +- drivers/net/irda/w83977af_ir.c | 62 +++++----- 22 files changed, 520 insertions(+), 519 deletions(-) (limited to 'drivers') diff --git a/drivers/net/irda/act200l-sir.c b/drivers/net/irda/act200l-sir.c index d8b89c74aab..37ab8c85571 100644 --- a/drivers/net/irda/act200l-sir.c +++ b/drivers/net/irda/act200l-sir.c @@ -107,7 +107,7 @@ static int act200l_open(struct sir_dev *dev) { struct qos_info *qos = &dev->qos; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); /* Power on the dongle */ sirdev_set_dtr_rts(dev, TRUE, TRUE); @@ -124,7 +124,7 @@ static int act200l_open(struct sir_dev *dev) static int act200l_close(struct sir_dev *dev) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); /* Power off the dongle */ sirdev_set_dtr_rts(dev, FALSE, FALSE); @@ -143,7 +143,7 @@ static int act200l_change_speed(struct sir_dev *dev, unsigned speed) u8 control[3]; int ret = 0; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); /* Clear DTR and set RTS to enter command mode */ sirdev_set_dtr_rts(dev, FALSE, TRUE); @@ -212,7 +212,7 @@ static int act200l_reset(struct sir_dev *dev) }; int ret = 0; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); switch (state) { case SIRDEV_STATE_DONGLE_RESET: @@ -240,7 +240,7 @@ static int act200l_reset(struct sir_dev *dev) dev->speed = 9600; break; default: - IRDA_ERROR("%s(), unknown state %d\n", __FUNCTION__, state); + IRDA_ERROR("%s(), unknown state %d\n", __func__, state); ret = -1; break; } diff --git a/drivers/net/irda/actisys-sir.c b/drivers/net/irda/actisys-sir.c index 736d2473b7e..50b2141a610 100644 --- a/drivers/net/irda/actisys-sir.c +++ b/drivers/net/irda/actisys-sir.c @@ -165,7 +165,7 @@ static int actisys_change_speed(struct sir_dev *dev, unsigned speed) int ret = 0; int i = 0; - IRDA_DEBUG(4, "%s(), speed=%d (was %d)\n", __FUNCTION__, + IRDA_DEBUG(4, "%s(), speed=%d (was %d)\n", __func__, speed, dev->speed); /* dongle was already resetted from irda_request state machine, diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index 083b0dd70fe..2ff181861d2 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -152,7 +152,7 @@ static int __init ali_ircc_init(void) int reg, revision; int i = 0; - IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__); ret = platform_driver_register(&ali_ircc_driver); if (ret) { @@ -166,7 +166,7 @@ static int __init ali_ircc_init(void) /* Probe for all the ALi chipsets we know about */ for (chip= chips; chip->name; chip++, i++) { - IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__, chip->name); + IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __func__, chip->name); /* Try all config registers for this chip */ for (cfg=0; cfg<2; cfg++) @@ -196,11 +196,11 @@ static int __init ali_ircc_init(void) if (reg == chip->cid_value) { - IRDA_DEBUG(2, "%s(), Chip found at 0x%03x\n", __FUNCTION__, cfg_base); + IRDA_DEBUG(2, "%s(), Chip found at 0x%03x\n", __func__, cfg_base); outb(0x1F, cfg_base); revision = inb(cfg_base+1); - IRDA_DEBUG(2, "%s(), Found %s chip, revision=%d\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), Found %s chip, revision=%d\n", __func__, chip->name, revision); /* @@ -223,14 +223,14 @@ static int __init ali_ircc_init(void) } else { - IRDA_DEBUG(2, "%s(), No %s chip at 0x%03x\n", __FUNCTION__, chip->name, cfg_base); + IRDA_DEBUG(2, "%s(), No %s chip at 0x%03x\n", __func__, chip->name, cfg_base); } /* Exit configuration */ outb(0xbb, cfg_base); } } - IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __func__); if (ret) platform_driver_unregister(&ali_ircc_driver); @@ -248,7 +248,7 @@ static void __exit ali_ircc_cleanup(void) { int i; - IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__); for (i=0; i < ARRAY_SIZE(dev_self); i++) { if (dev_self[i]) @@ -257,7 +257,7 @@ static void __exit ali_ircc_cleanup(void) platform_driver_unregister(&ali_ircc_driver); - IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __func__); } /* @@ -273,11 +273,11 @@ static int ali_ircc_open(int i, chipio_t *info) int dongle_id; int err; - IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__); if (i >= ARRAY_SIZE(dev_self)) { IRDA_ERROR("%s(), maximum number of supported chips reached!\n", - __FUNCTION__); + __func__); return -ENOMEM; } @@ -288,7 +288,7 @@ static int ali_ircc_open(int i, chipio_t *info) dev = alloc_irdadev(sizeof(*self)); if (dev == NULL) { IRDA_ERROR("%s(), can't allocate memory for control block!\n", - __FUNCTION__); + __func__); return -ENOMEM; } @@ -312,7 +312,7 @@ static int ali_ircc_open(int i, chipio_t *info) /* Reserve the ioports that we need */ if (!request_region(self->io.fir_base, self->io.fir_ext, ALI_IRCC_DRIVER_NAME)) { - IRDA_WARNING("%s(), can't get iobase of 0x%03x\n", __FUNCTION__, + IRDA_WARNING("%s(), can't get iobase of 0x%03x\n", __func__, self->io.fir_base); err = -ENODEV; goto err_out1; @@ -370,19 +370,19 @@ static int ali_ircc_open(int i, chipio_t *info) err = register_netdev(dev); if (err) { - IRDA_ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); + IRDA_ERROR("%s(), register_netdev() failed!\n", __func__); goto err_out4; } IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name); /* Check dongle id */ dongle_id = ali_ircc_read_dongle_id(i, info); - IRDA_MESSAGE("%s(), %s, Found dongle: %s\n", __FUNCTION__, + IRDA_MESSAGE("%s(), %s, Found dongle: %s\n", __func__, ALI_IRCC_DRIVER_NAME, dongle_types[dongle_id]); self->io.dongle_id = dongle_id; - IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __func__); return 0; @@ -411,7 +411,7 @@ static int __exit ali_ircc_close(struct ali_ircc_cb *self) { int iobase; - IRDA_DEBUG(4, "%s(), ---------------- Start ----------------\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), ---------------- Start ----------------\n", __func__); IRDA_ASSERT(self != NULL, return -1;); @@ -421,7 +421,7 @@ static int __exit ali_ircc_close(struct ali_ircc_cb *self) unregister_netdev(self->netdev); /* Release the PORT that this driver is using */ - IRDA_DEBUG(4, "%s(), Releasing Region %03x\n", __FUNCTION__, self->io.fir_base); + IRDA_DEBUG(4, "%s(), Releasing Region %03x\n", __func__, self->io.fir_base); release_region(self->io.fir_base, self->io.fir_ext); if (self->tx_buff.head) @@ -435,7 +435,7 @@ static int __exit ali_ircc_close(struct ali_ircc_cb *self) dev_self[self->index] = NULL; free_netdev(self->netdev); - IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __func__); return 0; } @@ -478,7 +478,7 @@ static int ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info) int cfg_base = info->cfg_base; int hi, low, reg; - IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__); /* Enter Configuration */ outb(chip->entr1, cfg_base); @@ -497,13 +497,13 @@ static int ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info) info->sir_base = info->fir_base; - IRDA_DEBUG(2, "%s(), probing fir_base=0x%03x\n", __FUNCTION__, info->fir_base); + IRDA_DEBUG(2, "%s(), probing fir_base=0x%03x\n", __func__, info->fir_base); /* Read IRQ control register */ outb(0x70, cfg_base); reg = inb(cfg_base+1); info->irq = reg & 0x0f; - IRDA_DEBUG(2, "%s(), probing irq=%d\n", __FUNCTION__, info->irq); + IRDA_DEBUG(2, "%s(), probing irq=%d\n", __func__, info->irq); /* Read DMA channel */ outb(0x74, cfg_base); @@ -511,26 +511,26 @@ static int ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info) info->dma = reg & 0x07; if(info->dma == 0x04) - IRDA_WARNING("%s(), No DMA channel assigned !\n", __FUNCTION__); + IRDA_WARNING("%s(), No DMA channel assigned !\n", __func__); else - IRDA_DEBUG(2, "%s(), probing dma=%d\n", __FUNCTION__, info->dma); + IRDA_DEBUG(2, "%s(), probing dma=%d\n", __func__, info->dma); /* Read Enabled Status */ outb(0x30, cfg_base); reg = inb(cfg_base+1); info->enabled = (reg & 0x80) && (reg & 0x01); - IRDA_DEBUG(2, "%s(), probing enabled=%d\n", __FUNCTION__, info->enabled); + IRDA_DEBUG(2, "%s(), probing enabled=%d\n", __func__, info->enabled); /* Read Power Status */ outb(0x22, cfg_base); reg = inb(cfg_base+1); info->suspended = (reg & 0x20); - IRDA_DEBUG(2, "%s(), probing suspended=%d\n", __FUNCTION__, info->suspended); + IRDA_DEBUG(2, "%s(), probing suspended=%d\n", __func__, info->suspended); /* Exit configuration */ outb(0xbb, cfg_base); - IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __func__); return 0; } @@ -548,7 +548,7 @@ static int ali_ircc_setup(chipio_t *info) int version; int iobase = info->fir_base; - IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__); /* Locking comments : * Most operations here need to be protected. We are called before @@ -609,7 +609,7 @@ static int ali_ircc_setup(chipio_t *info) // outb(UART_IER_RDI, iobase+UART_IER); //benjamin 2000/11/23 01:25PM // Turn on the interrupts in ali_ircc_net_open - IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__); return 0; } @@ -626,7 +626,7 @@ static int ali_ircc_read_dongle_id (int i, chipio_t *info) int dongle_id, reg; int cfg_base = info->cfg_base; - IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__); /* Enter Configuration */ outb(chips[i].entr1, cfg_base); @@ -640,13 +640,13 @@ static int ali_ircc_read_dongle_id (int i, chipio_t *info) outb(0xf0, cfg_base); reg = inb(cfg_base+1); dongle_id = ((reg>>6)&0x02) | ((reg>>5)&0x01); - IRDA_DEBUG(2, "%s(), probing dongle_id=%d, dongle_types=%s\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), probing dongle_id=%d, dongle_types=%s\n", __func__, dongle_id, dongle_types[dongle_id]); /* Exit configuration */ outb(0xbb, cfg_base); - IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__); return dongle_id; } @@ -663,7 +663,7 @@ static irqreturn_t ali_ircc_interrupt(int irq, void *dev_id) struct ali_ircc_cb *self; int ret; - IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__); self = dev->priv; @@ -677,7 +677,7 @@ static irqreturn_t ali_ircc_interrupt(int irq, void *dev_id) spin_unlock(&self->lock); - IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__); return ret; } /* @@ -691,7 +691,7 @@ static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self) __u8 eir, OldMessageCount; int iobase, tmp; - IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __func__); iobase = self->io.fir_base; @@ -704,10 +704,10 @@ static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self) //self->ier = inb(iobase+FIR_IER); 2000/12/1 04:32PM eir = self->InterruptID & self->ier; /* Mask out the interesting ones */ - IRDA_DEBUG(1, "%s(), self->InterruptID = %x\n", __FUNCTION__,self->InterruptID); - IRDA_DEBUG(1, "%s(), self->LineStatus = %x\n", __FUNCTION__,self->LineStatus); - IRDA_DEBUG(1, "%s(), self->ier = %x\n", __FUNCTION__,self->ier); - IRDA_DEBUG(1, "%s(), eir = %x\n", __FUNCTION__,eir); + IRDA_DEBUG(1, "%s(), self->InterruptID = %x\n", __func__,self->InterruptID); + IRDA_DEBUG(1, "%s(), self->LineStatus = %x\n", __func__,self->LineStatus); + IRDA_DEBUG(1, "%s(), self->ier = %x\n", __func__,self->ier); + IRDA_DEBUG(1, "%s(), eir = %x\n", __func__,eir); /* Disable interrupts */ SetCOMInterrupts(self, FALSE); @@ -718,7 +718,7 @@ static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self) { if (self->io.direction == IO_XMIT) /* TX */ { - IRDA_DEBUG(1, "%s(), ******* IIR_EOM (Tx) *******\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), ******* IIR_EOM (Tx) *******\n", __func__); if(ali_ircc_dma_xmit_complete(self)) { @@ -737,23 +737,23 @@ static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self) } else /* RX */ { - IRDA_DEBUG(1, "%s(), ******* IIR_EOM (Rx) *******\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), ******* IIR_EOM (Rx) *******\n", __func__); if(OldMessageCount > ((self->LineStatus+1) & 0x07)) { self->rcvFramesOverflow = TRUE; - IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE ******** \n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE ******** \n", __func__); } if (ali_ircc_dma_receive_complete(self)) { - IRDA_DEBUG(1, "%s(), ******* receive complete ******** \n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), ******* receive complete ******** \n", __func__); self->ier = IER_EOM; } else { - IRDA_DEBUG(1, "%s(), ******* Not receive complete ******** \n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), ******* Not receive complete ******** \n", __func__); self->ier = IER_EOM | IER_TIMER; } @@ -766,7 +766,7 @@ static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self) if(OldMessageCount > ((self->LineStatus+1) & 0x07)) { self->rcvFramesOverflow = TRUE; - IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE ******* \n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE ******* \n", __func__); } /* Disable Timer */ switch_bank(iobase, BANK1); @@ -798,7 +798,7 @@ static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self) /* Restore Interrupt */ SetCOMInterrupts(self, TRUE); - IRDA_DEBUG(1, "%s(), ----------------- End ---------------\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), ----------------- End ---------------\n", __func__); return IRQ_RETVAL(eir); } @@ -813,7 +813,7 @@ static irqreturn_t ali_ircc_sir_interrupt(struct ali_ircc_cb *self) int iobase; int iir, lsr; - IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__); iobase = self->io.sir_base; @@ -822,13 +822,13 @@ static irqreturn_t ali_ircc_sir_interrupt(struct ali_ircc_cb *self) /* Clear interrupt */ lsr = inb(iobase+UART_LSR); - IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", __FUNCTION__, + IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", __func__, iir, lsr, iobase); switch (iir) { case UART_IIR_RLSI: - IRDA_DEBUG(2, "%s(), RLSI\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), RLSI\n", __func__); break; case UART_IIR_RDI: /* Receive interrupt */ @@ -842,14 +842,14 @@ static irqreturn_t ali_ircc_sir_interrupt(struct ali_ircc_cb *self) } break; default: - IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n", __FUNCTION__, iir); + IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n", __func__, iir); break; } } - IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__); return IRQ_RETVAL(iir); } @@ -866,7 +866,7 @@ static void ali_ircc_sir_receive(struct ali_ircc_cb *self) int boguscount = 0; int iobase; - IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__); IRDA_ASSERT(self != NULL, return;); iobase = self->io.sir_base; @@ -881,12 +881,12 @@ static void ali_ircc_sir_receive(struct ali_ircc_cb *self) /* Make sure we don't stay here too long */ if (boguscount++ > 32) { - IRDA_DEBUG(2,"%s(), breaking!\n", __FUNCTION__); + IRDA_DEBUG(2,"%s(), breaking!\n", __func__); break; } } while (inb(iobase+UART_LSR) & UART_LSR_DR); - IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ ); } /* @@ -903,7 +903,7 @@ static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self) IRDA_ASSERT(self != NULL, return;); - IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ ); iobase = self->io.sir_base; @@ -922,16 +922,16 @@ static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self) { /* We must wait until all data are gone */ while(!(inb(iobase+UART_LSR) & UART_LSR_TEMT)) - IRDA_DEBUG(1, "%s(), UART_LSR_THRE\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), UART_LSR_THRE\n", __func__ ); - IRDA_DEBUG(1, "%s(), Changing speed! self->new_speed = %d\n", __FUNCTION__ , self->new_speed); + IRDA_DEBUG(1, "%s(), Changing speed! self->new_speed = %d\n", __func__ , self->new_speed); ali_ircc_change_speed(self, self->new_speed); self->new_speed = 0; // benjamin 2000/11/10 06:32PM if (self->io.speed > 115200) { - IRDA_DEBUG(2, "%s(), ali_ircc_change_speed from UART_LSR_TEMT \n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ali_ircc_change_speed from UART_LSR_TEMT \n", __func__ ); self->ier = IER_EOM; // SetCOMInterrupts(self, TRUE); @@ -949,7 +949,7 @@ static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self) outb(UART_IER_RDI, iobase+UART_IER); } - IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ ); } static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud) @@ -957,9 +957,9 @@ static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud) struct net_device *dev = self->netdev; int iobase; - IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __func__ ); - IRDA_DEBUG(2, "%s(), setting speed = %d \n", __FUNCTION__ , baud); + IRDA_DEBUG(2, "%s(), setting speed = %d \n", __func__ , baud); /* This function *must* be called with irq off and spin-lock. * - Jean II */ @@ -998,7 +998,7 @@ static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud) netif_wake_queue(self->netdev); - IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ ); } static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 baud) @@ -1008,14 +1008,14 @@ static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 baud) struct ali_ircc_cb *self = (struct ali_ircc_cb *) priv; struct net_device *dev; - IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __func__ ); IRDA_ASSERT(self != NULL, return;); dev = self->netdev; iobase = self->io.fir_base; - IRDA_DEBUG(1, "%s(), self->io.speed = %d, change to speed = %d\n", __FUNCTION__ ,self->io.speed,baud); + IRDA_DEBUG(1, "%s(), self->io.speed = %d, change to speed = %d\n", __func__ ,self->io.speed,baud); /* Come from SIR speed */ if(self->io.speed <=115200) @@ -1029,7 +1029,7 @@ static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 baud) // Set Dongle Speed mode ali_ircc_change_dongle_speed(self, baud); - IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ ); } /* @@ -1047,9 +1047,9 @@ static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed) int lcr; /* Line control reg */ int divisor; - IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __func__ ); - IRDA_DEBUG(1, "%s(), Setting speed to: %d\n", __FUNCTION__ , speed); + IRDA_DEBUG(1, "%s(), Setting speed to: %d\n", __func__ , speed); IRDA_ASSERT(self != NULL, return;); @@ -1103,7 +1103,7 @@ static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed) spin_unlock_irqrestore(&self->lock, flags); - IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ ); } static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed) @@ -1113,14 +1113,14 @@ static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed) int iobase,dongle_id; int tmp = 0; - IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __func__ ); iobase = self->io.fir_base; /* or iobase = self->io.sir_base; */ dongle_id = self->io.dongle_id; /* We are already locked, no need to do it again */ - IRDA_DEBUG(1, "%s(), Set Speed for %s , Speed = %d\n", __FUNCTION__ , dongle_types[dongle_id], speed); + IRDA_DEBUG(1, "%s(), Set Speed for %s , Speed = %d\n", __func__ , dongle_types[dongle_id], speed); switch_bank(iobase, BANK2); tmp = inb(iobase+FIR_IRDA_CR); @@ -1284,7 +1284,7 @@ static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed) switch_bank(iobase, BANK0); - IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ ); } /* @@ -1297,11 +1297,11 @@ static int ali_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len) { int actual = 0; - IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ ); /* Tx FIFO should be empty! */ if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { - IRDA_DEBUG(0, "%s(), failed, fifo not empty!\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), failed, fifo not empty!\n", __func__ ); return 0; } @@ -1313,7 +1313,7 @@ static int ali_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len) actual++; } - IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ ); return actual; } @@ -1329,7 +1329,7 @@ static int ali_ircc_net_open(struct net_device *dev) int iobase; char hwname[32]; - IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ ); IRDA_ASSERT(dev != NULL, return -1;); @@ -1375,7 +1375,7 @@ static int ali_ircc_net_open(struct net_device *dev) */ self->irlap = irlap_open(dev, &self->qos, hwname); - IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ ); return 0; } @@ -1392,7 +1392,7 @@ static int ali_ircc_net_close(struct net_device *dev) struct ali_ircc_cb *self; //int iobase; - IRDA_DEBUG(4, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s(), ---------------- Start ----------------\n", __func__ ); IRDA_ASSERT(dev != NULL, return -1;); @@ -1415,7 +1415,7 @@ static int ali_ircc_net_close(struct net_device *dev) free_irq(self->io.irq, dev); free_dma(self->io.dma); - IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ ); return 0; } @@ -1434,7 +1434,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) __u32 speed; int mtt, diff; - IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __func__ ); self = (struct ali_ircc_cb *) dev->priv; iobase = self->io.fir_base; @@ -1488,7 +1488,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) diff = self->now.tv_usec - self->stamp.tv_usec; /* self->stamp is set from ali_ircc_dma_receive_complete() */ - IRDA_DEBUG(1, "%s(), ******* diff = %d ******* \n", __FUNCTION__ , diff); + IRDA_DEBUG(1, "%s(), ******* diff = %d ******* \n", __func__ , diff); if (diff < 0) diff += 1000000; @@ -1510,7 +1510,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) /* Adjust for timer resolution */ mtt = (mtt+250) / 500; /* 4 discard, 5 get advanced, Let's round off */ - IRDA_DEBUG(1, "%s(), ************** mtt = %d ***********\n", __FUNCTION__ , mtt); + IRDA_DEBUG(1, "%s(), ************** mtt = %d ***********\n", __func__ , mtt); /* Setup timer */ if (mtt == 1) /* 500 us */ @@ -1567,7 +1567,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&self->lock, flags); dev_kfree_skb(skb); - IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ ); return 0; } @@ -1578,7 +1578,7 @@ static void ali_ircc_dma_xmit(struct ali_ircc_cb *self) unsigned char FIFO_OPTI, Hi, Lo; - IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __func__ ); iobase = self->io.fir_base; @@ -1629,7 +1629,7 @@ static void ali_ircc_dma_xmit(struct ali_ircc_cb *self) tmp = inb(iobase+FIR_LCR_B); tmp &= ~0x20; // Disable SIP outb(((unsigned char)(tmp & 0x3f) | LCR_B_TX_MODE) & ~LCR_B_BW, iobase+FIR_LCR_B); - IRDA_DEBUG(1, "%s(), ******* Change to TX mode: FIR_LCR_B = 0x%x ******* \n", __FUNCTION__ , inb(iobase+FIR_LCR_B)); + IRDA_DEBUG(1, "%s(), ******* Change to TX mode: FIR_LCR_B = 0x%x ******* \n", __func__ , inb(iobase+FIR_LCR_B)); outb(0, iobase+FIR_LSR); @@ -1639,7 +1639,7 @@ static void ali_ircc_dma_xmit(struct ali_ircc_cb *self) switch_bank(iobase, BANK0); - IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ ); } static int ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self) @@ -1647,7 +1647,7 @@ static int ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self) int iobase; int ret = TRUE; - IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __func__ ); iobase = self->io.fir_base; @@ -1660,7 +1660,7 @@ static int ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self) if((inb(iobase+FIR_LSR) & LSR_FRAME_ABORT) == LSR_FRAME_ABORT) { - IRDA_ERROR("%s(), ********* LSR_FRAME_ABORT *********\n", __FUNCTION__); + IRDA_ERROR("%s(), ********* LSR_FRAME_ABORT *********\n", __func__); self->stats.tx_errors++; self->stats.tx_fifo_errors++; } @@ -1703,7 +1703,7 @@ static int ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self) switch_bank(iobase, BANK0); - IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ ); return ret; } @@ -1718,7 +1718,7 @@ static int ali_ircc_dma_receive(struct ali_ircc_cb *self) { int iobase, tmp; - IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __func__ ); iobase = self->io.fir_base; @@ -1756,7 +1756,7 @@ static int ali_ircc_dma_receive(struct ali_ircc_cb *self) //switch_bank(iobase, BANK0); tmp = inb(iobase+FIR_LCR_B); outb((unsigned char)(tmp &0x3f) | LCR_B_RX_MODE | LCR_B_BW , iobase + FIR_LCR_B); // 2000/12/1 05:16PM - IRDA_DEBUG(1, "%s(), *** Change To RX mode: FIR_LCR_B = 0x%x *** \n", __FUNCTION__ , inb(iobase+FIR_LCR_B)); + IRDA_DEBUG(1, "%s(), *** Change To RX mode: FIR_LCR_B = 0x%x *** \n", __func__ , inb(iobase+FIR_LCR_B)); /* Set Rx Threshold */ switch_bank(iobase, BANK1); @@ -1768,7 +1768,7 @@ static int ali_ircc_dma_receive(struct ali_ircc_cb *self) outb(CR_DMA_EN | CR_DMA_BURST, iobase+FIR_CR); switch_bank(iobase, BANK0); - IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ ); return 0; } @@ -1779,7 +1779,7 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) __u8 status, MessageCount; int len, i, iobase, val; - IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __func__ ); st_fifo = &self->st_fifo; iobase = self->io.fir_base; @@ -1788,7 +1788,7 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) MessageCount = inb(iobase+ FIR_LSR)&0x07; if (MessageCount > 0) - IRDA_DEBUG(0, "%s(), Messsage count = %d,\n", __FUNCTION__ , MessageCount); + IRDA_DEBUG(0, "%s(), Messsage count = %d,\n", __func__ , MessageCount); for (i=0; i<=MessageCount; i++) { @@ -1801,11 +1801,11 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) len = len << 8; len |= inb(iobase+FIR_RX_DSR_LO); - IRDA_DEBUG(1, "%s(), RX Length = 0x%.2x,\n", __FUNCTION__ , len); - IRDA_DEBUG(1, "%s(), RX Status = 0x%.2x,\n", __FUNCTION__ , status); + IRDA_DEBUG(1, "%s(), RX Length = 0x%.2x,\n", __func__ , len); + IRDA_DEBUG(1, "%s(), RX Status = 0x%.2x,\n", __func__ , status); if (st_fifo->tail >= MAX_RX_WINDOW) { - IRDA_DEBUG(0, "%s(), window is full!\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), window is full!\n", __func__ ); continue; } @@ -1828,7 +1828,7 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) /* Check for errors */ if ((status & 0xd8) || self->rcvFramesOverflow || (len==0)) { - IRDA_DEBUG(0,"%s(), ************* RX Errors ************ \n", __FUNCTION__ ); + IRDA_DEBUG(0,"%s(), ************* RX Errors ************ \n", __func__ ); /* Skip frame */ self->stats.rx_errors++; @@ -1838,29 +1838,29 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) if (status & LSR_FIFO_UR) { self->stats.rx_frame_errors++; - IRDA_DEBUG(0,"%s(), ************* FIFO Errors ************ \n", __FUNCTION__ ); + IRDA_DEBUG(0,"%s(), ************* FIFO Errors ************ \n", __func__ ); } if (status & LSR_FRAME_ERROR) { self->stats.rx_frame_errors++; - IRDA_DEBUG(0,"%s(), ************* FRAME Errors ************ \n", __FUNCTION__ ); + IRDA_DEBUG(0,"%s(), ************* FRAME Errors ************ \n", __func__ ); } if (status & LSR_CRC_ERROR) { self->stats.rx_crc_errors++; - IRDA_DEBUG(0,"%s(), ************* CRC Errors ************ \n", __FUNCTION__ ); + IRDA_DEBUG(0,"%s(), ************* CRC Errors ************ \n", __func__ ); } if(self->rcvFramesOverflow) { self->stats.rx_frame_errors++; - IRDA_DEBUG(0,"%s(), ************* Overran DMA buffer ************ \n", __FUNCTION__ ); + IRDA_DEBUG(0,"%s(), ************* Overran DMA buffer ************ \n", __func__ ); } if(len == 0) { self->stats.rx_frame_errors++; - IRDA_DEBUG(0,"%s(), ********** Receive Frame Size = 0 ********* \n", __FUNCTION__ ); + IRDA_DEBUG(0,"%s(), ********** Receive Frame Size = 0 ********* \n", __func__ ); } } else @@ -1872,7 +1872,7 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) val = inb(iobase+FIR_BSR); if ((val& BSR_FIFO_NOT_EMPTY)== 0x80) { - IRDA_DEBUG(0, "%s(), ************* BSR_FIFO_NOT_EMPTY ************ \n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), ************* BSR_FIFO_NOT_EMPTY ************ \n", __func__ ); /* Put this entry back in fifo */ st_fifo->head--; @@ -1909,7 +1909,7 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) { IRDA_WARNING("%s(), memory squeeze, " "dropping frame.\n", - __FUNCTION__); + __func__); self->stats.rx_dropped++; return FALSE; @@ -1937,7 +1937,7 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) switch_bank(iobase, BANK0); - IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ ); return TRUE; } @@ -1956,7 +1956,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) int iobase; __u32 speed; - IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ ); IRDA_ASSERT(dev != NULL, return 0;); @@ -2005,7 +2005,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ ); return 0; } @@ -2024,7 +2024,7 @@ static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) unsigned long flags; int ret = 0; - IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ ); IRDA_ASSERT(dev != NULL, return -1;); @@ -2032,11 +2032,11 @@ static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) IRDA_ASSERT(self != NULL, return -1;); - IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__ , dev->name, cmd); + IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __func__ , dev->name, cmd); switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ - IRDA_DEBUG(1, "%s(), SIOCSBANDWIDTH\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), SIOCSBANDWIDTH\n", __func__ ); /* * This function will also be used by IrLAP to change the * speed, so we still must allow for speed change within @@ -2050,13 +2050,13 @@ static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) spin_unlock_irqrestore(&self->lock, flags); break; case SIOCSMEDIABUSY: /* Set media busy */ - IRDA_DEBUG(1, "%s(), SIOCSMEDIABUSY\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), SIOCSMEDIABUSY\n", __func__ ); if (!capable(CAP_NET_ADMIN)) return -EPERM; irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ - IRDA_DEBUG(2, "%s(), SIOCGRECEIVING\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), SIOCGRECEIVING\n", __func__ ); /* This is protected */ irq->ifr_receiving = ali_ircc_is_receiving(self); break; @@ -2064,7 +2064,7 @@ static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ret = -EOPNOTSUPP; } - IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ ); return ret; } @@ -2081,7 +2081,7 @@ static int ali_ircc_is_receiving(struct ali_ircc_cb *self) int status = FALSE; int iobase; - IRDA_DEBUG(2, "%s(), ---------------- Start -----------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ---------------- Start -----------------\n", __func__ ); IRDA_ASSERT(self != NULL, return FALSE;); @@ -2095,7 +2095,7 @@ static int ali_ircc_is_receiving(struct ali_ircc_cb *self) if((inb(iobase+FIR_FIFO_FR) & 0x3f) != 0) { /* We are receiving something */ - IRDA_DEBUG(1, "%s(), We are receiving something\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), We are receiving something\n", __func__ ); status = TRUE; } switch_bank(iobase, BANK0); @@ -2107,7 +2107,7 @@ static int ali_ircc_is_receiving(struct ali_ircc_cb *self) spin_unlock_irqrestore(&self->lock, flags); - IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ ); return status; } @@ -2116,9 +2116,9 @@ static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev) { struct ali_ircc_cb *self = (struct ali_ircc_cb *) dev->priv; - IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ ); - IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ ); return &self->stats; } @@ -2164,7 +2164,7 @@ static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable) int iobase = self->io.fir_base; /* or sir_base */ - IRDA_DEBUG(2, "%s(), -------- Start -------- ( Enable = %d )\n", __FUNCTION__ , enable); + IRDA_DEBUG(2, "%s(), -------- Start -------- ( Enable = %d )\n", __func__ , enable); /* Enable the interrupt which we wish to */ if (enable){ @@ -2205,14 +2205,14 @@ static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable) else outb(newMask, iobase+UART_IER); - IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ ); } static void SIR2FIR(int iobase) { //unsigned char tmp; - IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __func__ ); /* Already protected (change_speed() or setup()), no need to lock. * Jean II */ @@ -2228,14 +2228,14 @@ static void SIR2FIR(int iobase) //tmp |= 0x20; //outb(tmp, iobase+FIR_LCR_B); - IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ ); } static void FIR2SIR(int iobase) { unsigned char val; - IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __func__ ); /* Already protected (change_speed() or setup()), no need to lock. * Jean II */ @@ -2251,7 +2251,7 @@ static void FIR2SIR(int iobase) val = inb(iobase+UART_LSR); val = inb(iobase+UART_MSR); - IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ ); } MODULE_AUTHOR("Benjamin Kong "); diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 34ad189fff6..69d16b30323 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -245,7 +245,7 @@ toshoboe_dumpregs (struct toshoboe_cb *self) { __u32 ringbase; - IRDA_DEBUG (4, "%s()\n", __FUNCTION__); + IRDA_DEBUG (4, "%s()\n", __func__); ringbase = INB (OBOE_RING_BASE0) << 10; ringbase |= INB (OBOE_RING_BASE1) << 18; @@ -293,7 +293,7 @@ static void toshoboe_disablebm (struct toshoboe_cb *self) { __u8 command; - IRDA_DEBUG (4, "%s()\n", __FUNCTION__); + IRDA_DEBUG (4, "%s()\n", __func__); pci_read_config_byte (self->pdev, PCI_COMMAND, &command); command &= ~PCI_COMMAND_MASTER; @@ -305,7 +305,7 @@ toshoboe_disablebm (struct toshoboe_cb *self) static void toshoboe_stopchip (struct toshoboe_cb *self) { - IRDA_DEBUG (4, "%s()\n", __FUNCTION__); + IRDA_DEBUG (4, "%s()\n", __func__); /*Disable interrupts */ OUTB (0x0, OBOE_IER); @@ -350,7 +350,7 @@ toshoboe_setbaud (struct toshoboe_cb *self) __u16 pconfig = 0; __u8 config0l = 0; - IRDA_DEBUG (2, "%s(%d/%d)\n", __FUNCTION__, self->speed, self->io.speed); + IRDA_DEBUG (2, "%s(%d/%d)\n", __func__, self->speed, self->io.speed); switch (self->speed) { @@ -482,7 +482,7 @@ toshoboe_setbaud (struct toshoboe_cb *self) static void toshoboe_enablebm (struct toshoboe_cb *self) { - IRDA_DEBUG (4, "%s()\n", __FUNCTION__); + IRDA_DEBUG (4, "%s()\n", __func__); pci_set_master (self->pdev); } @@ -492,7 +492,7 @@ toshoboe_initring (struct toshoboe_cb *self) { int i; - IRDA_DEBUG (4, "%s()\n", __FUNCTION__); + IRDA_DEBUG (4, "%s()\n", __func__); for (i = 0; i < TX_SLOTS; ++i) { @@ -550,7 +550,7 @@ toshoboe_startchip (struct toshoboe_cb *self) { __u32 physaddr; - IRDA_DEBUG (4, "%s()\n", __FUNCTION__); + IRDA_DEBUG (4, "%s()\n", __func__); toshoboe_initring (self); toshoboe_enablebm (self); @@ -824,7 +824,7 @@ toshoboe_probe (struct toshoboe_cb *self) #endif unsigned long flags; - IRDA_DEBUG (4, "%s()\n", __FUNCTION__); + IRDA_DEBUG (4, "%s()\n", __func__); if (request_irq (self->io.irq, toshoboe_probeinterrupt, self->io.irqflags, "toshoboe", (void *) self)) @@ -983,10 +983,10 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) IRDA_ASSERT (self != NULL, return 0; ); - IRDA_DEBUG (1, "%s.tx:%x(%x)%x\n", __FUNCTION__ + IRDA_DEBUG (1, "%s.tx:%x(%x)%x\n", __func__ ,skb->len,self->txpending,INB (OBOE_ENABLEH)); if (!cb->magic) { - IRDA_DEBUG (2, "%s.Not IrLAP:%x\n", __FUNCTION__, cb->magic); + IRDA_DEBUG (2, "%s.Not IrLAP:%x\n", __func__, cb->magic); #ifdef DUMP_PACKETS _dumpbufs(skb->data,skb->len,'>'); #endif @@ -1015,7 +1015,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) { self->new_speed = speed; IRDA_DEBUG (1, "%s: Queued TxDone scheduled speed change %d\n" , - __FUNCTION__, speed); + __func__, speed); /* if no data, that's all! */ if (!skb->len) { @@ -1057,7 +1057,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) /* which we will add a wrong checksum to */ mtt = toshoboe_makemttpacket (self, self->tx_bufs[self->txs], mtt); - IRDA_DEBUG (1, "%s.mtt:%x(%x)%d\n", __FUNCTION__ + IRDA_DEBUG (1, "%s.mtt:%x(%x)%d\n", __func__ ,skb->len,mtt,self->txpending); if (mtt) { @@ -1101,7 +1101,7 @@ dumpbufs(skb->data,skb->len,'>'); if (self->ring->tx[self->txs].control & OBOE_CTL_TX_HW_OWNS) { - IRDA_DEBUG (0, "%s.ful:%x(%x)%x\n", __FUNCTION__ + IRDA_DEBUG (0, "%s.ful:%x(%x)%x\n", __func__ ,skb->len, self->ring->tx[self->txs].control, self->txpending); toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX); spin_unlock_irqrestore(&self->spinlock, flags); @@ -1179,7 +1179,7 @@ toshoboe_interrupt (int irq, void *dev_id) if (self->ring->tx[i].control & OBOE_CTL_TX_HW_OWNS) self->txpending++; } - IRDA_DEBUG (1, "%s.txd(%x)%x/%x\n", __FUNCTION__ + IRDA_DEBUG (1, "%s.txd(%x)%x/%x\n", __func__ ,irqstat,txp,self->txpending); txp = INB (OBOE_TXSLOT) & OBOE_SLOT_MASK; @@ -1209,7 +1209,7 @@ toshoboe_interrupt (int irq, void *dev_id) { self->speed = self->new_speed; IRDA_DEBUG (1, "%s: Executed TxDone scheduled speed change %d\n", - __FUNCTION__, self->speed); + __func__, self->speed); toshoboe_setbaud (self); } @@ -1224,7 +1224,7 @@ toshoboe_interrupt (int irq, void *dev_id) { int len = self->ring->rx[self->rxs].len; skb = NULL; - IRDA_DEBUG (3, "%s.rcv:%x(%x)\n", __FUNCTION__ + IRDA_DEBUG (3, "%s.rcv:%x(%x)\n", __func__ ,len,self->ring->rx[self->rxs].control); #ifdef DUMP_PACKETS @@ -1246,7 +1246,7 @@ dumpbufs(self->rx_bufs[self->rxs],len,'<'); len -= 2; else len = 0; - IRDA_DEBUG (1, "%s.SIR:%x(%x)\n", __FUNCTION__, len,enable); + IRDA_DEBUG (1, "%s.SIR:%x(%x)\n", __func__, len,enable); } #ifdef USE_MIR @@ -1256,7 +1256,7 @@ dumpbufs(self->rx_bufs[self->rxs],len,'<'); len -= 2; else len = 0; - IRDA_DEBUG (2, "%s.MIR:%x(%x)\n", __FUNCTION__, len,enable); + IRDA_DEBUG (2, "%s.MIR:%x(%x)\n", __func__, len,enable); } #endif else if (enable & OBOE_ENABLEH_FIRON) @@ -1265,10 +1265,10 @@ dumpbufs(self->rx_bufs[self->rxs],len,'<'); len -= 4; /*FIXME: check this */ else len = 0; - IRDA_DEBUG (1, "%s.FIR:%x(%x)\n", __FUNCTION__, len,enable); + IRDA_DEBUG (1, "%s.FIR:%x(%x)\n", __func__, len,enable); } else - IRDA_DEBUG (0, "%s.?IR:%x(%x)\n", __FUNCTION__, len,enable); + IRDA_DEBUG (0, "%s.?IR:%x(%x)\n", __func__, len,enable); if (len) { @@ -1289,7 +1289,7 @@ dumpbufs(self->rx_bufs[self->rxs],len,'<'); { printk (KERN_INFO "%s(), memory squeeze, dropping frame.\n", - __FUNCTION__); + __func__); } } } @@ -1301,7 +1301,7 @@ dumpbufs(self->rx_bufs[self->rxs],len,'<'); /* (SIR) data is splitted in several slots. */ /* we have to join all the received buffers received */ /*in a large buffer before checking CRC. */ - IRDA_DEBUG (0, "%s.err:%x(%x)\n", __FUNCTION__ + IRDA_DEBUG (0, "%s.err:%x(%x)\n", __func__ ,len,self->ring->rx[self->rxs].control); } @@ -1329,7 +1329,7 @@ dumpbufs(self->rx_bufs[self->rxs],len,'<'); if (irqstat & OBOE_INT_SIP) { self->int_sip++; - IRDA_DEBUG (1, "%s.sip:%x(%x)%x\n", __FUNCTION__ + IRDA_DEBUG (1, "%s.sip:%x(%x)%x\n", __func__ ,self->int_sip,irqstat,self->txpending); } return IRQ_HANDLED; @@ -1343,7 +1343,7 @@ toshoboe_net_open (struct net_device *dev) unsigned long flags; int rc; - IRDA_DEBUG (4, "%s()\n", __FUNCTION__); + IRDA_DEBUG (4, "%s()\n", __func__); self = netdev_priv(dev); @@ -1381,7 +1381,7 @@ toshoboe_net_close (struct net_device *dev) { struct toshoboe_cb *self; - IRDA_DEBUG (4, "%s()\n", __FUNCTION__); + IRDA_DEBUG (4, "%s()\n", __func__); IRDA_ASSERT (dev != NULL, return -1; ); self = (struct toshoboe_cb *) dev->priv; @@ -1426,7 +1426,7 @@ toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) IRDA_ASSERT (self != NULL, return -1; ); - IRDA_DEBUG (5, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd); + IRDA_DEBUG (5, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); /* Disable interrupts & save flags */ spin_lock_irqsave(&self->spinlock, flags); @@ -1438,7 +1438,7 @@ toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) * speed, so we still must allow for speed change within * interrupt context. */ - IRDA_DEBUG (1, "%s(BANDWIDTH), %s, (%X/%ld\n", __FUNCTION__ + IRDA_DEBUG (1, "%s(BANDWIDTH), %s, (%X/%ld\n", __func__ ,dev->name, INB (OBOE_STATUS), irq->ifr_baudrate ); if (!in_interrupt () && !capable (CAP_NET_ADMIN)) { ret = -EPERM; @@ -1451,7 +1451,7 @@ toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) self->new_speed = irq->ifr_baudrate; break; case SIOCSMEDIABUSY: /* Set media busy */ - IRDA_DEBUG (1, "%s(MEDIABUSY), %s, (%X/%x)\n", __FUNCTION__ + IRDA_DEBUG (1, "%s(MEDIABUSY), %s, (%X/%x)\n", __func__ ,dev->name, INB (OBOE_STATUS), capable (CAP_NET_ADMIN) ); if (!capable (CAP_NET_ADMIN)) { ret = -EPERM; @@ -1461,11 +1461,11 @@ toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) break; case SIOCGRECEIVING: /* Check if we are receiving right now */ irq->ifr_receiving = (INB (OBOE_STATUS) & OBOE_STATUS_RXBUSY) ? 1 : 0; - IRDA_DEBUG (3, "%s(RECEIVING), %s, (%X/%x)\n", __FUNCTION__ + IRDA_DEBUG (3, "%s(RECEIVING), %s, (%X/%x)\n", __func__ ,dev->name, INB (OBOE_STATUS), irq->ifr_receiving ); break; default: - IRDA_DEBUG (1, "%s(?), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd); + IRDA_DEBUG (1, "%s(?), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); ret = -EOPNOTSUPP; } out: @@ -1492,7 +1492,7 @@ toshoboe_close (struct pci_dev *pci_dev) int i; struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev); - IRDA_DEBUG (4, "%s()\n", __FUNCTION__); + IRDA_DEBUG (4, "%s()\n", __func__); IRDA_ASSERT (self != NULL, return; ); @@ -1533,7 +1533,7 @@ toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid) int ok = 0; int err; - IRDA_DEBUG (4, "%s()\n", __FUNCTION__); + IRDA_DEBUG (4, "%s()\n", __func__); if ((err=pci_enable_device(pci_dev))) return err; @@ -1700,7 +1700,7 @@ toshoboe_gotosleep (struct pci_dev *pci_dev, pm_message_t crap) unsigned long flags; int i = 10; - IRDA_DEBUG (4, "%s()\n", __FUNCTION__); + IRDA_DEBUG (4, "%s()\n", __func__); if (!self || self->stopped) return 0; @@ -1728,7 +1728,7 @@ toshoboe_wakeup (struct pci_dev *pci_dev) struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev); unsigned long flags; - IRDA_DEBUG (4, "%s()\n", __FUNCTION__); + IRDA_DEBUG (4, "%s()\n", __func__); if (!self || !self->stopped) return 0; diff --git a/drivers/net/irda/girbil-sir.c b/drivers/net/irda/girbil-sir.c index 738531b16bd..a31b8fa8aaa 100644 --- a/drivers/net/irda/girbil-sir.c +++ b/drivers/net/irda/girbil-sir.c @@ -86,7 +86,7 @@ static int girbil_open(struct sir_dev *dev) { struct qos_info *qos = &dev->qos; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* Power on dongle */ sirdev_set_dtr_rts(dev, TRUE, TRUE); @@ -102,7 +102,7 @@ static int girbil_open(struct sir_dev *dev) static int girbil_close(struct sir_dev *dev) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* Power off dongle */ sirdev_set_dtr_rts(dev, FALSE, FALSE); @@ -126,7 +126,7 @@ static int girbil_change_speed(struct sir_dev *dev, unsigned speed) u8 control[2]; static int ret = 0; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* dongle alread reset - port and dongle at default speed */ @@ -179,7 +179,7 @@ static int girbil_change_speed(struct sir_dev *dev, unsigned speed) break; default: - IRDA_ERROR("%s - undefined state %d\n", __FUNCTION__, state); + IRDA_ERROR("%s - undefined state %d\n", __func__, state); ret = -EINVAL; break; } @@ -209,7 +209,7 @@ static int girbil_reset(struct sir_dev *dev) u8 control = GIRBIL_TXEN | GIRBIL_RXEN; int ret = 0; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); switch (state) { case SIRDEV_STATE_DONGLE_RESET: @@ -241,7 +241,7 @@ static int girbil_reset(struct sir_dev *dev) break; default: - IRDA_ERROR("%s(), undefined state %d\n", __FUNCTION__, state); + IRDA_ERROR("%s(), undefined state %d\n", __func__, state); ret = -1; break; } diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 18b471cd144..b5d6b9ac162 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -177,12 +177,12 @@ static void irda_usb_build_header(struct irda_usb_cb *self, (!force) && (self->speed != -1)) { /* No speed and xbofs change here * (we'll do it later in the write callback) */ - IRDA_DEBUG(2, "%s(), not changing speed yet\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), not changing speed yet\n", __func__); *header = 0; return; } - IRDA_DEBUG(2, "%s(), changing speed to %d\n", __FUNCTION__, self->new_speed); + IRDA_DEBUG(2, "%s(), changing speed to %d\n", __func__, self->new_speed); self->speed = self->new_speed; /* We will do ` self->new_speed = -1; ' in the completion * handler just in case the current URB fail - Jean II */ @@ -228,7 +228,7 @@ static void irda_usb_build_header(struct irda_usb_cb *self, /* Set the negotiated additional XBOFS */ if (self->new_xbofs != -1) { - IRDA_DEBUG(2, "%s(), changing xbofs to %d\n", __FUNCTION__, self->new_xbofs); + IRDA_DEBUG(2, "%s(), changing xbofs to %d\n", __func__, self->new_xbofs); self->xbofs = self->new_xbofs; /* We will do ` self->new_xbofs = -1; ' in the completion * handler just in case the current URB fail - Jean II */ @@ -302,13 +302,13 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self) struct urb *urb; int ret; - IRDA_DEBUG(2, "%s(), speed=%d, xbofs=%d\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), speed=%d, xbofs=%d\n", __func__, self->new_speed, self->new_xbofs); /* Grab the speed URB */ urb = self->speed_urb; if (urb->status != 0) { - IRDA_WARNING("%s(), URB still in use!\n", __FUNCTION__); + IRDA_WARNING("%s(), URB still in use!\n", __func__); return; } @@ -334,7 +334,7 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self) /* Irq disabled -> GFP_ATOMIC */ if ((ret = usb_submit_urb(urb, GFP_ATOMIC))) { - IRDA_WARNING("%s(), failed Speed URB\n", __FUNCTION__); + IRDA_WARNING("%s(), failed Speed URB\n", __func__); } } @@ -347,7 +347,7 @@ static void speed_bulk_callback(struct urb *urb) { struct irda_usb_cb *self = urb->context; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* We should always have a context */ IRDA_ASSERT(self != NULL, return;); @@ -357,7 +357,7 @@ static void speed_bulk_callback(struct urb *urb) /* Check for timeout and other USB nasties */ if (urb->status != 0) { /* I get a lot of -ECONNABORTED = -103 here - Jean II */ - IRDA_DEBUG(0, "%s(), URB complete status %d, transfer_flags 0x%04X\n", __FUNCTION__, urb->status, urb->transfer_flags); + IRDA_DEBUG(0, "%s(), URB complete status %d, transfer_flags 0x%04X\n", __func__, urb->status, urb->transfer_flags); /* Don't do anything here, that might confuse the USB layer. * Instead, we will wait for irda_usb_net_timeout(), the @@ -392,7 +392,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) int res, mtt; int err = 1; /* Failed */ - IRDA_DEBUG(4, "%s() on %s\n", __FUNCTION__, netdev->name); + IRDA_DEBUG(4, "%s() on %s\n", __func__, netdev->name); netif_stop_queue(netdev); @@ -403,7 +403,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) * We need to check self->present under the spinlock because * of irda_usb_disconnect() is synchronous - Jean II */ if (!self->present) { - IRDA_DEBUG(0, "%s(), Device is gone...\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), Device is gone...\n", __func__); goto drop; } @@ -437,7 +437,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) } if (urb->status != 0) { - IRDA_WARNING("%s(), URB still in use!\n", __FUNCTION__); + IRDA_WARNING("%s(), URB still in use!\n", __func__); goto drop; } @@ -524,7 +524,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) /* Ask USB to send the packet - Irq disabled -> GFP_ATOMIC */ if ((res = usb_submit_urb(urb, GFP_ATOMIC))) { - IRDA_WARNING("%s(), failed Tx URB\n", __FUNCTION__); + IRDA_WARNING("%s(), failed Tx URB\n", __func__); self->stats.tx_errors++; /* Let USB recover : We will catch that in the watchdog */ /*netif_start_queue(netdev);*/ @@ -556,7 +556,7 @@ static void write_bulk_callback(struct urb *urb) struct sk_buff *skb = urb->context; struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* We should always have a context */ IRDA_ASSERT(self != NULL, return;); @@ -570,7 +570,7 @@ static void write_bulk_callback(struct urb *urb) /* Check for timeout and other USB nasties */ if (urb->status != 0) { /* I get a lot of -ECONNABORTED = -103 here - Jean II */ - IRDA_DEBUG(0, "%s(), URB complete status %d, transfer_flags 0x%04X\n", __FUNCTION__, urb->status, urb->transfer_flags); + IRDA_DEBUG(0, "%s(), URB complete status %d, transfer_flags 0x%04X\n", __func__, urb->status, urb->transfer_flags); /* Don't do anything here, that might confuse the USB layer, * and we could go in recursion and blow the kernel stack... @@ -589,7 +589,7 @@ static void write_bulk_callback(struct urb *urb) /* If the network is closed, stop everything */ if ((!self->netopen) || (!self->present)) { - IRDA_DEBUG(0, "%s(), Network is gone...\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), Network is gone...\n", __func__); spin_unlock_irqrestore(&self->lock, flags); return; } @@ -600,7 +600,7 @@ static void write_bulk_callback(struct urb *urb) (self->new_xbofs != self->xbofs)) { /* We haven't changed speed yet (because of * IUC_SPEED_BUG), so do it now - Jean II */ - IRDA_DEBUG(1, "%s(), Changing speed now...\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), Changing speed now...\n", __func__); irda_usb_change_speed_xbofs(self); } else { /* New speed and xbof is now commited in hardware */ @@ -632,7 +632,7 @@ static void irda_usb_net_timeout(struct net_device *netdev) struct urb *urb; int done = 0; /* If we have made any progress */ - IRDA_DEBUG(0, "%s(), Network layer thinks we timed out!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), Network layer thinks we timed out!\n", __func__); IRDA_ASSERT(self != NULL, return;); /* Protect us from USB callbacks, net Tx and else. */ @@ -640,7 +640,7 @@ static void irda_usb_net_timeout(struct net_device *netdev) /* self->present *MUST* be read under spinlock */ if (!self->present) { - IRDA_WARNING("%s(), device not present!\n", __FUNCTION__); + IRDA_WARNING("%s(), device not present!\n", __func__); netif_stop_queue(netdev); spin_unlock_irqrestore(&self->lock, flags); return; @@ -763,7 +763,7 @@ static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, struc struct irda_skb_cb *cb; int ret; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* This should never happen */ IRDA_ASSERT(skb != NULL, return;); @@ -786,7 +786,7 @@ static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, struc /* If this ever happen, we are in deep s***. * Basically, the Rx path will stop... */ IRDA_WARNING("%s(), Failed to submit Rx URB %d\n", - __FUNCTION__, ret); + __func__, ret); } } @@ -807,7 +807,7 @@ static void irda_usb_receive(struct urb *urb) struct urb *next_urb; unsigned int len, docopy; - IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, urb->actual_length); + IRDA_DEBUG(2, "%s(), len=%d\n", __func__, urb->actual_length); /* Find ourselves */ cb = (struct irda_skb_cb *) skb->cb; @@ -817,7 +817,7 @@ static void irda_usb_receive(struct urb *urb) /* If the network is closed or the device gone, stop everything */ if ((!self->netopen) || (!self->present)) { - IRDA_DEBUG(0, "%s(), Network is gone!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), Network is gone!\n", __func__); /* Don't re-submit the URB : will stall the Rx path */ return; } @@ -840,7 +840,7 @@ static void irda_usb_receive(struct urb *urb) /* Usually precursor to a hot-unplug on OHCI. */ default: self->stats.rx_errors++; - IRDA_DEBUG(0, "%s(), RX status %d, transfer_flags 0x%04X \n", __FUNCTION__, urb->status, urb->transfer_flags); + IRDA_DEBUG(0, "%s(), RX status %d, transfer_flags 0x%04X \n", __func__, urb->status, urb->transfer_flags); break; } /* If we received an error, we don't want to resubmit the @@ -861,7 +861,7 @@ static void irda_usb_receive(struct urb *urb) /* Check for empty frames */ if (urb->actual_length <= self->header_length) { - IRDA_WARNING("%s(), empty frame!\n", __FUNCTION__); + IRDA_WARNING("%s(), empty frame!\n", __func__); goto done; } @@ -967,7 +967,7 @@ static void irda_usb_rx_defer_expired(unsigned long data) struct irda_skb_cb *cb; struct urb *next_urb; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* Find ourselves */ cb = (struct irda_skb_cb *) skb->cb; @@ -1053,7 +1053,7 @@ static int stir421x_fw_upload(struct irda_usb_cb *self, patch_block, block_size, &actual_len, msecs_to_jiffies(500)); IRDA_DEBUG(3,"%s(): Bulk send %u bytes, ret=%d\n", - __FUNCTION__, actual_len, ret); + __func__, actual_len, ret); if (ret < 0) break; @@ -1092,7 +1092,7 @@ static int stir421x_patch_device(struct irda_usb_cb *self) /* We get a patch from userspace */ IRDA_MESSAGE("%s(): Received firmware %s (%zu bytes)\n", - __FUNCTION__, stir421x_fw_name, fw->size); + __func__, stir421x_fw_name, fw->size); ret = -EINVAL; @@ -1116,7 +1116,7 @@ static int stir421x_patch_device(struct irda_usb_cb *self) + (build % 10); IRDA_DEBUG(3, "%s(): Firmware Product version %ld\n", - __FUNCTION__, fw_version); + __func__, fw_version); } } @@ -1172,7 +1172,7 @@ static int irda_usb_net_open(struct net_device *netdev) char hwname[16]; int i; - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); + IRDA_DEBUG(1, "%s()\n", __func__); IRDA_ASSERT(netdev != NULL, return -1;); self = (struct irda_usb_cb *) netdev->priv; @@ -1182,13 +1182,13 @@ static int irda_usb_net_open(struct net_device *netdev) /* Can only open the device if it's there */ if(!self->present) { spin_unlock_irqrestore(&self->lock, flags); - IRDA_WARNING("%s(), device not present!\n", __FUNCTION__); + IRDA_WARNING("%s(), device not present!\n", __func__); return -1; } if(self->needspatch) { spin_unlock_irqrestore(&self->lock, flags); - IRDA_WARNING("%s(), device needs patch\n", __FUNCTION__) ; + IRDA_WARNING("%s(), device needs patch\n", __func__) ; return -EIO ; } @@ -1231,7 +1231,7 @@ static int irda_usb_net_open(struct net_device *netdev) /* If this ever happen, we are in deep s***. * Basically, we can't start the Rx path... */ IRDA_WARNING("%s(), Failed to allocate Rx skb\n", - __FUNCTION__); + __func__); return -1; } //skb_reserve(newskb, USB_IRDA_HEADER - 1); @@ -1254,7 +1254,7 @@ static int irda_usb_net_close(struct net_device *netdev) struct irda_usb_cb *self; int i; - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); + IRDA_DEBUG(1, "%s()\n", __func__); IRDA_ASSERT(netdev != NULL, return -1;); self = (struct irda_usb_cb *) netdev->priv; @@ -1309,7 +1309,7 @@ static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) self = dev->priv; IRDA_ASSERT(self != NULL, return -1;); - IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd); + IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ @@ -1367,7 +1367,7 @@ static inline void irda_usb_init_qos(struct irda_usb_cb *self) { struct irda_class_desc *desc; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); desc = self->irda_desc; @@ -1384,7 +1384,7 @@ static inline void irda_usb_init_qos(struct irda_usb_cb *self) self->qos.data_size.bits = desc->bmDataSize; IRDA_DEBUG(0, "%s(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", - __FUNCTION__, self->qos.baud_rate.bits, self->qos.data_size.bits, self->qos.window_size.bits, self->qos.additional_bofs.bits, self->qos.min_turn_time.bits); + __func__, self->qos.baud_rate.bits, self->qos.data_size.bits, self->qos.window_size.bits, self->qos.additional_bofs.bits, self->qos.min_turn_time.bits); /* Don't always trust what the dongle tell us */ if(self->capability & IUC_SIR_ONLY) @@ -1419,7 +1419,7 @@ static inline int irda_usb_open(struct irda_usb_cb *self) { struct net_device *netdev = self->netdev; - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); + IRDA_DEBUG(1, "%s()\n", __func__); irda_usb_init_qos(self); @@ -1442,7 +1442,7 @@ static inline int irda_usb_open(struct irda_usb_cb *self) */ static inline void irda_usb_close(struct irda_usb_cb *self) { - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); + IRDA_DEBUG(1, "%s()\n", __func__); /* Remove netdevice */ unregister_netdev(self->netdev); @@ -1515,13 +1515,13 @@ static inline int irda_usb_parse_endpoints(struct irda_usb_cb *self, struct usb_ /* This is our interrupt endpoint */ self->bulk_int_ep = ep; } else { - IRDA_ERROR("%s(), Unrecognised endpoint %02X.\n", __FUNCTION__, ep); + IRDA_ERROR("%s(), Unrecognised endpoint %02X.\n", __func__, ep); } } } IRDA_DEBUG(0, "%s(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n", - __FUNCTION__, self->bulk_in_ep, self->bulk_out_ep, self->bulk_out_mtu, self->bulk_int_ep); + __func__, self->bulk_in_ep, self->bulk_out_ep, self->bulk_out_mtu, self->bulk_int_ep); return((self->bulk_in_ep != 0) && (self->bulk_out_ep != 0)); } @@ -1583,7 +1583,7 @@ static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_interf 0, intf->altsetting->desc.bInterfaceNumber, desc, sizeof(*desc), 500); - IRDA_DEBUG(1, "%s(), ret=%d\n", __FUNCTION__, ret); + IRDA_DEBUG(1, "%s(), ret=%d\n", __func__, ret); if (ret < sizeof(*desc)) { IRDA_WARNING("usb-irda: class_descriptor read %s (%d)\n", (ret<0) ? "failed" : "too short", ret); @@ -1696,10 +1696,10 @@ static int irda_usb_probe(struct usb_interface *intf, /* Martin Diehl says if we get a -EPIPE we should * be fine and we don't need to do a usb_clear_halt(). * - Jean II */ - IRDA_DEBUG(0, "%s(), Received -EPIPE, ignoring...\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), Received -EPIPE, ignoring...\n", __func__); break; default: - IRDA_DEBUG(0, "%s(), Unknown error %d\n", __FUNCTION__, ret); + IRDA_DEBUG(0, "%s(), Unknown error %d\n", __func__, ret); ret = -EIO; goto err_out_3; } @@ -1708,7 +1708,7 @@ static int irda_usb_probe(struct usb_interface *intf, interface = intf->cur_altsetting; if(!irda_usb_parse_endpoints(self, interface->endpoint, interface->desc.bNumEndpoints)) { - IRDA_ERROR("%s(), Bogus endpoints...\n", __FUNCTION__); + IRDA_ERROR("%s(), Bogus endpoints...\n", __func__); ret = -EIO; goto err_out_3; } @@ -1815,7 +1815,7 @@ static void irda_usb_disconnect(struct usb_interface *intf) struct irda_usb_cb *self = usb_get_intfdata(intf); int i; - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); + IRDA_DEBUG(1, "%s()\n", __func__); usb_set_intfdata(intf, NULL); if (!self) @@ -1865,7 +1865,7 @@ static void irda_usb_disconnect(struct usb_interface *intf) /* Free self and network device */ free_netdev(self->netdev); - IRDA_DEBUG(0, "%s(), USB IrDA Disconnected\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), USB IrDA Disconnected\n", __func__); } /*------------------------------------------------------------------*/ diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index 9e33196f945..6bcee01c684 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -231,7 +231,7 @@ static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp, dev = priv->dev; if (!dev) { - IRDA_WARNING("%s(), not ready yet!\n", __FUNCTION__); + IRDA_WARNING("%s(), not ready yet!\n", __func__); return; } @@ -388,7 +388,7 @@ static int irtty_ioctl(struct tty_struct *tty, struct file *file, unsigned int c IRDA_ASSERT(priv != NULL, return -ENODEV;); IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -EBADR;); - IRDA_DEBUG(3, "%s(cmd=0x%X)\n", __FUNCTION__, cmd); + IRDA_DEBUG(3, "%s(cmd=0x%X)\n", __func__, cmd); dev = priv->dev; IRDA_ASSERT(dev != NULL, return -1;); @@ -476,7 +476,7 @@ static int irtty_open(struct tty_struct *tty) mutex_unlock(&irtty_mutex); - IRDA_DEBUG(0, "%s - %s: irda line discipline opened\n", __FUNCTION__, tty->name); + IRDA_DEBUG(0, "%s - %s: irda line discipline opened\n", __func__, tty->name); return 0; @@ -528,7 +528,7 @@ static void irtty_close(struct tty_struct *tty) kfree(priv); - IRDA_DEBUG(0, "%s - %s: irda line discipline closed\n", __FUNCTION__, tty->name); + IRDA_DEBUG(0, "%s - %s: irda line discipline closed\n", __func__, tty->name); } /* ------------------------------------------------------- */ @@ -566,7 +566,7 @@ static void __exit irtty_sir_cleanup(void) if ((err = tty_unregister_ldisc(N_IRDA))) { IRDA_ERROR("%s(), can't unregister line discipline (err = %d)\n", - __FUNCTION__, err); + __func__, err); } } diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c index 648e54b3f00..73fe83be34f 100644 --- a/drivers/net/irda/kingsun-sir.c +++ b/drivers/net/irda/kingsun-sir.c @@ -243,7 +243,7 @@ static void kingsun_rcv_irq(struct urb *urb) } } else if (urb->actual_length > 0) { err("%s(): Unexpected response length, expected %d got %d", - __FUNCTION__, kingsun->max_rx, urb->actual_length); + __func__, kingsun->max_rx, urb->actual_length); } /* This urb has already been filled in kingsun_net_open */ ret = usb_submit_urb(urb, GFP_ATOMIC); diff --git a/drivers/net/irda/litelink-sir.c b/drivers/net/irda/litelink-sir.c index 73261c54bbf..d6d9d2e5ad4 100644 --- a/drivers/net/irda/litelink-sir.c +++ b/drivers/net/irda/litelink-sir.c @@ -78,7 +78,7 @@ static int litelink_open(struct sir_dev *dev) { struct qos_info *qos = &dev->qos; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* Power up dongle */ sirdev_set_dtr_rts(dev, TRUE, TRUE); @@ -95,7 +95,7 @@ static int litelink_open(struct sir_dev *dev) static int litelink_close(struct sir_dev *dev) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* Power off dongle */ sirdev_set_dtr_rts(dev, FALSE, FALSE); @@ -113,7 +113,7 @@ static int litelink_change_speed(struct sir_dev *dev, unsigned speed) { int i; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* dongle already reset by irda-thread - current speed (dongle and * port) is the default speed (115200 for litelink!) @@ -156,7 +156,7 @@ static int litelink_change_speed(struct sir_dev *dev, unsigned speed) */ static int litelink_reset(struct sir_dev *dev) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* probably the power-up can be dropped here, but with only * 15 usec delay it's not worth the risk unless somebody with diff --git a/drivers/net/irda/ma600-sir.c b/drivers/net/irda/ma600-sir.c index 809906d9476..1ceed9cfb7c 100644 --- a/drivers/net/irda/ma600-sir.c +++ b/drivers/net/irda/ma600-sir.c @@ -67,13 +67,13 @@ static struct dongle_driver ma600 = { static int __init ma600_sir_init(void) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); return irda_register_dongle(&ma600); } static void __exit ma600_sir_cleanup(void) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); irda_unregister_dongle(&ma600); } @@ -88,7 +88,7 @@ static int ma600_open(struct sir_dev *dev) { struct qos_info *qos = &dev->qos; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); sirdev_set_dtr_rts(dev, TRUE, TRUE); @@ -106,7 +106,7 @@ static int ma600_open(struct sir_dev *dev) static int ma600_close(struct sir_dev *dev) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* Power off dongle */ sirdev_set_dtr_rts(dev, FALSE, FALSE); @@ -176,7 +176,7 @@ static int ma600_change_speed(struct sir_dev *dev, unsigned speed) { u8 byte; - IRDA_DEBUG(2, "%s(), speed=%d (was %d)\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), speed=%d (was %d)\n", __func__, speed, dev->speed); /* dongle already reset, dongle and port at default speed (9600) */ @@ -201,12 +201,12 @@ static int ma600_change_speed(struct sir_dev *dev, unsigned speed) sirdev_raw_read(dev, &byte, sizeof(byte)); if (byte != get_control_byte(speed)) { IRDA_WARNING("%s(): bad control byte read-back %02x != %02x\n", - __FUNCTION__, (unsigned) byte, + __func__, (unsigned) byte, (unsigned) get_control_byte(speed)); return -1; } else - IRDA_DEBUG(2, "%s() control byte write read OK\n", __FUNCTION__); + IRDA_DEBUG(2, "%s() control byte write read OK\n", __func__); #endif /* Set DTR, Set RTS */ @@ -238,7 +238,7 @@ static int ma600_change_speed(struct sir_dev *dev, unsigned speed) int ma600_reset(struct sir_dev *dev) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* Reset the dongle : set DTR low for 10 ms */ sirdev_set_dtr_rts(dev, FALSE, TRUE); diff --git a/drivers/net/irda/mcp2120-sir.c b/drivers/net/irda/mcp2120-sir.c index 67bd016e4df..5e2f4859cee 100644 --- a/drivers/net/irda/mcp2120-sir.c +++ b/drivers/net/irda/mcp2120-sir.c @@ -63,7 +63,7 @@ static int mcp2120_open(struct sir_dev *dev) { struct qos_info *qos = &dev->qos; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* seems no explicit power-on required here and reset switching it on anyway */ @@ -76,7 +76,7 @@ static int mcp2120_open(struct sir_dev *dev) static int mcp2120_close(struct sir_dev *dev) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* Power off dongle */ /* reset and inhibit mcp2120 */ @@ -102,7 +102,7 @@ static int mcp2120_change_speed(struct sir_dev *dev, unsigned speed) u8 control[2]; static int ret = 0; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); switch (state) { case SIRDEV_STATE_DONGLE_SPEED: @@ -155,7 +155,7 @@ static int mcp2120_change_speed(struct sir_dev *dev, unsigned speed) break; default: - IRDA_ERROR("%s(), undefine state %d\n", __FUNCTION__, state); + IRDA_ERROR("%s(), undefine state %d\n", __func__, state); ret = -EINVAL; break; } @@ -187,7 +187,7 @@ static int mcp2120_reset(struct sir_dev *dev) unsigned delay = 0; int ret = 0; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); switch (state) { case SIRDEV_STATE_DONGLE_RESET: @@ -213,7 +213,7 @@ static int mcp2120_reset(struct sir_dev *dev) break; default: - IRDA_ERROR("%s(), undefined state %d\n", __FUNCTION__, state); + IRDA_ERROR("%s(), undefined state %d\n", __func__, state); ret = -EINVAL; break; } diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 18d17143537..8583d951a6a 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -223,7 +223,7 @@ static int __init nsc_ircc_init(void) /* Probe for all the NSC chipsets we know about */ for (chip = chips; chip->name ; chip++) { - IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __func__, chip->name); /* Try all config registers for this chip */ @@ -235,7 +235,7 @@ static int __init nsc_ircc_init(void) /* Read index register */ reg = inb(cfg_base); if (reg == 0xff) { - IRDA_DEBUG(2, "%s() no chip at 0x%03x\n", __FUNCTION__, cfg_base); + IRDA_DEBUG(2, "%s() no chip at 0x%03x\n", __func__, cfg_base); continue; } @@ -244,7 +244,7 @@ static int __init nsc_ircc_init(void) id = inb(cfg_base+1); if ((id & chip->cid_mask) == chip->cid_value) { IRDA_DEBUG(2, "%s() Found %s chip, revision=%d\n", - __FUNCTION__, chip->name, id & ~chip->cid_mask); + __func__, chip->name, id & ~chip->cid_mask); /* * If we found a correct PnP setting, @@ -295,7 +295,7 @@ static int __init nsc_ircc_init(void) } i++; } else { - IRDA_DEBUG(2, "%s(), Wrong chip id=0x%02x\n", __FUNCTION__, id); + IRDA_DEBUG(2, "%s(), Wrong chip id=0x%02x\n", __func__, id); } } } @@ -345,7 +345,7 @@ static int __init nsc_ircc_open(chipio_t *info) void *ret; int err, chip_index; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); for (chip_index = 0; chip_index < ARRAY_SIZE(dev_self); chip_index++) { @@ -354,7 +354,7 @@ static int __init nsc_ircc_open(chipio_t *info) } if (chip_index == ARRAY_SIZE(dev_self)) { - IRDA_ERROR("%s(), maximum number of supported chips reached!\n", __FUNCTION__); + IRDA_ERROR("%s(), maximum number of supported chips reached!\n", __func__); return -ENOMEM; } @@ -369,7 +369,7 @@ static int __init nsc_ircc_open(chipio_t *info) dev = alloc_irdadev(sizeof(struct nsc_ircc_cb)); if (dev == NULL) { IRDA_ERROR("%s(), can't allocate memory for " - "control block!\n", __FUNCTION__); + "control block!\n", __func__); return -ENOMEM; } @@ -393,7 +393,7 @@ static int __init nsc_ircc_open(chipio_t *info) ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name); if (!ret) { IRDA_WARNING("%s(), can't get iobase of 0x%03x\n", - __FUNCTION__, self->io.fir_base); + __func__, self->io.fir_base); err = -ENODEV; goto out1; } @@ -450,7 +450,7 @@ static int __init nsc_ircc_open(chipio_t *info) err = register_netdev(dev); if (err) { - IRDA_ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); + IRDA_ERROR("%s(), register_netdev() failed!\n", __func__); goto out4; } IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name); @@ -506,7 +506,7 @@ static int __exit nsc_ircc_close(struct nsc_ircc_cb *self) { int iobase; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return -1;); @@ -519,7 +519,7 @@ static int __exit nsc_ircc_close(struct nsc_ircc_cb *self) /* Release the PORT that this driver is using */ IRDA_DEBUG(4, "%s(), Releasing Region %03x\n", - __FUNCTION__, self->io.fir_base); + __func__, self->io.fir_base); release_region(self->io.fir_base, self->io.fir_ext); if (self->tx_buff.head) @@ -557,7 +557,7 @@ static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info) case 0x2e8: outb(0x15, cfg_base+1); break; case 0x3f8: outb(0x16, cfg_base+1); break; case 0x2f8: outb(0x17, cfg_base+1); break; - default: IRDA_ERROR("%s(), invalid base_address", __FUNCTION__); + default: IRDA_ERROR("%s(), invalid base_address", __func__); } /* Control Signal Routing Register (CSRT) */ @@ -569,7 +569,7 @@ static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info) case 9: temp = 0x05; break; case 11: temp = 0x06; break; case 15: temp = 0x07; break; - default: IRDA_ERROR("%s(), invalid irq", __FUNCTION__); + default: IRDA_ERROR("%s(), invalid irq", __func__); } outb(CFG_108_CSRT, cfg_base); @@ -577,7 +577,7 @@ static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info) case 0: outb(0x08+temp, cfg_base+1); break; case 1: outb(0x10+temp, cfg_base+1); break; case 3: outb(0x18+temp, cfg_base+1); break; - default: IRDA_ERROR("%s(), invalid dma", __FUNCTION__); + default: IRDA_ERROR("%s(), invalid dma", __func__); } outb(CFG_108_MCTL, cfg_base); /* Mode Control Register (MCTL) */ @@ -616,7 +616,7 @@ static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info) break; } info->sir_base = info->fir_base; - IRDA_DEBUG(2, "%s(), probing fir_base=0x%03x\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), probing fir_base=0x%03x\n", __func__, info->fir_base); /* Read control signals routing register (CSRT) */ @@ -649,7 +649,7 @@ static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info) info->irq = 15; break; } - IRDA_DEBUG(2, "%s(), probing irq=%d\n", __FUNCTION__, info->irq); + IRDA_DEBUG(2, "%s(), probing irq=%d\n", __func__, info->irq); /* Currently we only read Rx DMA but it will also be used for Tx */ switch ((reg >> 3) & 0x03) { @@ -666,7 +666,7 @@ static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info) info->dma = 3; break; } - IRDA_DEBUG(2, "%s(), probing dma=%d\n", __FUNCTION__, info->dma); + IRDA_DEBUG(2, "%s(), probing dma=%d\n", __func__, info->dma); /* Read mode control register (MCTL) */ outb(CFG_108_MCTL, cfg_base); @@ -823,7 +823,7 @@ static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info) /* User is sure about his config... accept it. */ IRDA_DEBUG(2, "%s(): nsc_ircc_init_39x (user settings): " "io=0x%04x, irq=%d, dma=%d\n", - __FUNCTION__, info->fir_base, info->irq, info->dma); + __func__, info->fir_base, info->irq, info->dma); /* Access bank for SP2 */ outb(CFG_39X_LDN, cfg_base); @@ -864,7 +864,7 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info) int enabled, susp; IRDA_DEBUG(2, "%s(), nsc_ircc_probe_39x, base=%d\n", - __FUNCTION__, cfg_base); + __func__, cfg_base); /* This function should be executed with irq off to avoid * another driver messing with the Super I/O bank - Jean II */ @@ -898,7 +898,7 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info) outb(CFG_39X_SPC, cfg_base); susp = 1 - ((inb(cfg_base+1) & 0x02) >> 1); - IRDA_DEBUG(2, "%s(): io=0x%02x%02x, irq=%d (type %d), rxdma=%d, txdma=%d, enabled=%d (suspended=%d)\n", __FUNCTION__, reg1,reg2,irq,irqt,dma1,dma2,enabled,susp); + IRDA_DEBUG(2, "%s(): io=0x%02x%02x, irq=%d (type %d), rxdma=%d, txdma=%d, enabled=%d (suspended=%d)\n", __func__, reg1,reg2,irq,irqt,dma1,dma2,enabled,susp); /* Configure SP2 */ @@ -950,7 +950,7 @@ static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *i pnp_info.dma = pnp_dma(dev, 0); IRDA_DEBUG(0, "%s() : From PnP, found firbase 0x%03X ; irq %d ; dma %d.\n", - __FUNCTION__, pnp_info.fir_base, pnp_info.irq, pnp_info.dma); + __func__, pnp_info.fir_base, pnp_info.irq, pnp_info.dma); if((pnp_info.fir_base == 0) || (pnp_info.irq == -1) || (pnp_info.dma == -1)) { @@ -979,7 +979,7 @@ static int nsc_ircc_setup(chipio_t *info) version = inb(iobase+MID); IRDA_DEBUG(2, "%s() Driver %s Found chip version %02x\n", - __FUNCTION__, driver_name, version); + __func__, driver_name, version); /* Should be 0x2? */ if (0x20 != (version & 0xf0)) { @@ -1083,30 +1083,30 @@ static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id) case 0x00: /* same as */ case 0x01: /* Differential serial interface */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", - __FUNCTION__, dongle_types[dongle_id]); + __func__, dongle_types[dongle_id]); break; case 0x02: /* same as */ case 0x03: /* Reserved */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", - __FUNCTION__, dongle_types[dongle_id]); + __func__, dongle_types[dongle_id]); break; case 0x04: /* Sharp RY5HD01 */ break; case 0x05: /* Reserved, but this is what the Thinkpad reports */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", - __FUNCTION__, dongle_types[dongle_id]); + __func__, dongle_types[dongle_id]); break; case 0x06: /* Single-ended serial interface */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", - __FUNCTION__, dongle_types[dongle_id]); + __func__, dongle_types[dongle_id]); break; case 0x07: /* Consumer-IR only */ IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n", - __FUNCTION__, dongle_types[dongle_id]); + __func__, dongle_types[dongle_id]); break; case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ IRDA_DEBUG(0, "%s(), %s\n", - __FUNCTION__, dongle_types[dongle_id]); + __func__, dongle_types[dongle_id]); break; case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ outb(0x28, iobase+7); /* Set irsl[0-2] as output */ @@ -1114,7 +1114,7 @@ static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id) case 0x0A: /* same as */ case 0x0B: /* Reserved */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", - __FUNCTION__, dongle_types[dongle_id]); + __func__, dongle_types[dongle_id]); break; case 0x0C: /* same as */ case 0x0D: /* HP HSDL-1100/HSDL-2100 */ @@ -1129,14 +1129,14 @@ static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id) break; case 0x0F: /* No dongle connected */ IRDA_DEBUG(0, "%s(), %s\n", - __FUNCTION__, dongle_types[dongle_id]); + __func__, dongle_types[dongle_id]); switch_bank(iobase, BANK0); outb(0x62, iobase+MCR); break; default: IRDA_DEBUG(0, "%s(), invalid dongle_id %#x", - __FUNCTION__, dongle_id); + __func__, dongle_id); } /* IRCFG1: IRSL1 and 2 are set to IrDA mode */ @@ -1168,30 +1168,30 @@ static void nsc_ircc_change_dongle_speed(int iobase, int speed, int dongle_id) case 0x00: /* same as */ case 0x01: /* Differential serial interface */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", - __FUNCTION__, dongle_types[dongle_id]); + __func__, dongle_types[dongle_id]); break; case 0x02: /* same as */ case 0x03: /* Reserved */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", - __FUNCTION__, dongle_types[dongle_id]); + __func__, dongle_types[dongle_id]); break; case 0x04: /* Sharp RY5HD01 */ break; case 0x05: /* Reserved */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", - __FUNCTION__, dongle_types[dongle_id]); + __func__, dongle_types[dongle_id]); break; case 0x06: /* Single-ended serial interface */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", - __FUNCTION__, dongle_types[dongle_id]); + __func__, dongle_types[dongle_id]); break; case 0x07: /* Consumer-IR only */ IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n", - __FUNCTION__, dongle_types[dongle_id]); + __func__, dongle_types[dongle_id]); break; case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ IRDA_DEBUG(0, "%s(), %s\n", - __FUNCTION__, dongle_types[dongle_id]); + __func__, dongle_types[dongle_id]); outb(0x00, iobase+4); if (speed > 115200) outb(0x01, iobase+4); @@ -1210,7 +1210,7 @@ static void nsc_ircc_change_dongle_speed(int iobase, int speed, int dongle_id) case 0x0A: /* same as */ case 0x0B: /* Reserved */ IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", - __FUNCTION__, dongle_types[dongle_id]); + __func__, dongle_types[dongle_id]); break; case 0x0C: /* same as */ case 0x0D: /* HP HSDL-1100/HSDL-2100 */ @@ -1219,13 +1219,13 @@ static void nsc_ircc_change_dongle_speed(int iobase, int speed, int dongle_id) break; case 0x0F: /* No dongle connected */ IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n", - __FUNCTION__, dongle_types[dongle_id]); + __func__, dongle_types[dongle_id]); switch_bank(iobase, BANK0); outb(0x62, iobase+MCR); break; default: - IRDA_DEBUG(0, "%s(), invalid data_rate\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), invalid data_rate\n", __func__); } /* Restore bank register */ outb(bank, iobase+BSR); @@ -1246,7 +1246,7 @@ static __u8 nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed) __u8 bank; __u8 ier; /* Interrupt enable register */ - IRDA_DEBUG(2, "%s(), speed=%d\n", __FUNCTION__, speed); + IRDA_DEBUG(2, "%s(), speed=%d\n", __func__, speed); IRDA_ASSERT(self != NULL, return 0;); @@ -1279,20 +1279,20 @@ static __u8 nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed) outb(inb(iobase+4) | 0x04, iobase+4); mcr = MCR_MIR; - IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __func__); break; case 1152000: mcr = MCR_MIR; - IRDA_DEBUG(0, "%s(), handling baud of 1152000\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), handling baud of 1152000\n", __func__); break; case 4000000: mcr = MCR_FIR; - IRDA_DEBUG(0, "%s(), handling baud of 4000000\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), handling baud of 4000000\n", __func__); break; default: mcr = MCR_FIR; IRDA_DEBUG(0, "%s(), unknown baud rate of %d\n", - __FUNCTION__, speed); + __func__, speed); break; } @@ -1597,7 +1597,7 @@ static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size) int actual = 0; __u8 bank; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); /* Save current bank */ bank = inb(iobase+BSR); @@ -1605,7 +1605,7 @@ static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size) switch_bank(iobase, BANK0); if (!(inb_p(iobase+LSR) & LSR_TXEMP)) { IRDA_DEBUG(4, "%s(), warning, FIFO not empty yet!\n", - __FUNCTION__); + __func__); /* FIFO may still be filled to the Tx interrupt threshold */ fifo_size -= 17; @@ -1618,7 +1618,7 @@ static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size) } IRDA_DEBUG(4, "%s(), fifo_size %d ; %d sent of %d\n", - __FUNCTION__, fifo_size, actual, len); + __func__, fifo_size, actual, len); /* Restore bank */ outb(bank, iobase+BSR); @@ -1639,7 +1639,7 @@ static int nsc_ircc_dma_xmit_complete(struct nsc_ircc_cb *self) __u8 bank; int ret = TRUE; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); iobase = self->io.fir_base; @@ -1770,7 +1770,7 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8); if (st_fifo->tail >= MAX_RX_WINDOW) { - IRDA_DEBUG(0, "%s(), window is full!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), window is full!\n", __func__); continue; } @@ -1862,7 +1862,7 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) if (skb == NULL) { IRDA_WARNING("%s(), memory squeeze, " "dropping frame.\n", - __FUNCTION__); + __func__); self->stats.rx_dropped++; /* Restore bank register */ @@ -1968,7 +1968,7 @@ static void nsc_ircc_sir_interrupt(struct nsc_ircc_cb *self, int eir) * Need to be after self->io.direction to avoid race with * nsc_ircc_hard_xmit_sir() - Jean II */ if (self->new_speed) { - IRDA_DEBUG(2, "%s(), Changing speed!\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), Changing speed!\n", __func__); self->ier = nsc_ircc_change_speed(self, self->new_speed); self->new_speed = 0; @@ -2054,7 +2054,7 @@ static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, } else IRDA_WARNING("%s(), potential " "Tx queue lockup !\n", - __FUNCTION__); + __func__); } } else { /* Not finished yet, so interrupt on DMA again */ @@ -2163,7 +2163,7 @@ static int nsc_ircc_net_open(struct net_device *dev) char hwname[32]; __u8 bank; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(dev != NULL, return -1;); self = (struct nsc_ircc_cb *) dev->priv; @@ -2225,7 +2225,7 @@ static int nsc_ircc_net_close(struct net_device *dev) int iobase; __u8 bank; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(dev != NULL, return -1;); @@ -2279,7 +2279,7 @@ static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) IRDA_ASSERT(self != NULL, return -1;); - IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd); + IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ diff --git a/drivers/net/irda/old_belkin-sir.c b/drivers/net/irda/old_belkin-sir.c index 8c22c7374a2..75714bc7103 100644 --- a/drivers/net/irda/old_belkin-sir.c +++ b/drivers/net/irda/old_belkin-sir.c @@ -92,7 +92,7 @@ static int old_belkin_open(struct sir_dev *dev) { struct qos_info *qos = &dev->qos; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* Power on dongle */ sirdev_set_dtr_rts(dev, TRUE, TRUE); @@ -110,7 +110,7 @@ static int old_belkin_open(struct sir_dev *dev) static int old_belkin_close(struct sir_dev *dev) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* Power off dongle */ sirdev_set_dtr_rts(dev, FALSE, FALSE); @@ -125,7 +125,7 @@ static int old_belkin_close(struct sir_dev *dev) */ static int old_belkin_change_speed(struct sir_dev *dev, unsigned speed) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); dev->speed = 9600; return (speed==dev->speed) ? 0 : -EINVAL; @@ -139,7 +139,7 @@ static int old_belkin_change_speed(struct sir_dev *dev, unsigned speed) */ static int old_belkin_reset(struct sir_dev *dev) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* This dongles speed "defaults" to 9600 bps ;-) */ dev->speed = 9600; diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index 6078e03de9a..3f32909c24c 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -80,7 +80,7 @@ static int sirdev_tx_complete_fsm(struct sir_dev *dev) return 0; default: - IRDA_ERROR("%s - undefined state\n", __FUNCTION__); + IRDA_ERROR("%s - undefined state\n", __func__); return -EINVAL; } fsm->substate = next_state; @@ -107,11 +107,11 @@ static void sirdev_config_fsm(struct work_struct *work) int ret = -1; unsigned delay; - IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies); + IRDA_DEBUG(2, "%s(), <%ld>\n", __func__, jiffies); do { IRDA_DEBUG(3, "%s - state=0x%04x / substate=0x%04x\n", - __FUNCTION__, fsm->state, fsm->substate); + __func__, fsm->state, fsm->substate); next_state = fsm->state; delay = 0; @@ -249,12 +249,12 @@ static void sirdev_config_fsm(struct work_struct *work) break; default: - IRDA_ERROR("%s - undefined state\n", __FUNCTION__); + IRDA_ERROR("%s - undefined state\n", __func__); fsm->result = -EINVAL; /* fall thru */ case SIRDEV_STATE_ERROR: - IRDA_ERROR("%s - error: %d\n", __FUNCTION__, fsm->result); + IRDA_ERROR("%s - error: %d\n", __func__, fsm->result); #if 0 /* don't enable this before we have netdev->tx_timeout to recover */ netif_stop_queue(dev->netdev); @@ -284,11 +284,12 @@ int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned par { struct sir_fsm *fsm = &dev->fsm; - IRDA_DEBUG(2, "%s - state=0x%04x / param=%u\n", __FUNCTION__, initial_state, param); + IRDA_DEBUG(2, "%s - state=0x%04x / param=%u\n", __func__, + initial_state, param); if (down_trylock(&fsm->sem)) { if (in_interrupt() || in_atomic() || irqs_disabled()) { - IRDA_DEBUG(1, "%s(), state machine busy!\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), state machine busy!\n", __func__); return -EWOULDBLOCK; } else down(&fsm->sem); @@ -296,7 +297,7 @@ int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned par if (fsm->state == SIRDEV_STATE_DEAD) { /* race with sirdev_close should never happen */ - IRDA_ERROR("%s(), instance staled!\n", __FUNCTION__); + IRDA_ERROR("%s(), instance staled!\n", __func__); up(&fsm->sem); return -ESTALE; /* or better EPIPE? */ } @@ -341,7 +342,7 @@ int sirdev_set_dongle(struct sir_dev *dev, IRDA_DONGLE type) { int err; - IRDA_DEBUG(3, "%s : requesting dongle %d.\n", __FUNCTION__, type); + IRDA_DEBUG(3, "%s : requesting dongle %d.\n", __func__, type); err = sirdev_schedule_dongle_open(dev, type); if (unlikely(err)) @@ -376,7 +377,7 @@ int sirdev_raw_write(struct sir_dev *dev, const char *buf, int len) ret = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len); if (ret > 0) { - IRDA_DEBUG(3, "%s(), raw-tx started\n", __FUNCTION__); + IRDA_DEBUG(3, "%s(), raw-tx started\n", __func__); dev->tx_buff.data += ret; dev->tx_buff.len -= ret; @@ -437,7 +438,7 @@ void sirdev_write_complete(struct sir_dev *dev) spin_lock_irqsave(&dev->tx_lock, flags); IRDA_DEBUG(3, "%s() - dev->tx_buff.len = %d\n", - __FUNCTION__, dev->tx_buff.len); + __func__, dev->tx_buff.len); if (likely(dev->tx_buff.len > 0)) { /* Write data left in transmit buffer */ @@ -450,7 +451,7 @@ void sirdev_write_complete(struct sir_dev *dev) else if (unlikely(actual<0)) { /* could be dropped later when we have tx_timeout to recover */ IRDA_ERROR("%s: drv->do_write failed (%d)\n", - __FUNCTION__, actual); + __func__, actual); if ((skb=dev->tx_skb) != NULL) { dev->tx_skb = NULL; dev_kfree_skb_any(skb); @@ -471,7 +472,7 @@ void sirdev_write_complete(struct sir_dev *dev) * restarted when the irda-thread has completed the request. */ - IRDA_DEBUG(3, "%s(), raw-tx done\n", __FUNCTION__); + IRDA_DEBUG(3, "%s(), raw-tx done\n", __func__); dev->raw_tx = 0; goto done; /* no post-frame handling in raw mode */ } @@ -488,7 +489,7 @@ void sirdev_write_complete(struct sir_dev *dev) * re-activated. */ - IRDA_DEBUG(5, "%s(), finished with frame!\n", __FUNCTION__); + IRDA_DEBUG(5, "%s(), finished with frame!\n", __func__); if ((skb=dev->tx_skb) != NULL) { dev->tx_skb = NULL; @@ -498,14 +499,14 @@ void sirdev_write_complete(struct sir_dev *dev) } if (unlikely(dev->new_speed > 0)) { - IRDA_DEBUG(5, "%s(), Changing speed!\n", __FUNCTION__); + IRDA_DEBUG(5, "%s(), Changing speed!\n", __func__); err = sirdev_schedule_speed(dev, dev->new_speed); if (unlikely(err)) { /* should never happen * forget the speed change and hope the stack recovers */ IRDA_ERROR("%s - schedule speed change failed: %d\n", - __FUNCTION__, err); + __func__, err); netif_wake_queue(dev->netdev); } /* else: success @@ -532,13 +533,13 @@ EXPORT_SYMBOL(sirdev_write_complete); int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count) { if (!dev || !dev->netdev) { - IRDA_WARNING("%s(), not ready yet!\n", __FUNCTION__); + IRDA_WARNING("%s(), not ready yet!\n", __func__); return -1; } if (!dev->irlap) { IRDA_WARNING("%s - too early: %p / %zd!\n", - __FUNCTION__, cp, count); + __func__, cp, count); return -1; } @@ -548,7 +549,7 @@ int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count) */ irda_device_set_media_busy(dev->netdev, TRUE); dev->stats.rx_dropped++; - IRDA_DEBUG(0, "%s; rx-drop: %zd\n", __FUNCTION__, count); + IRDA_DEBUG(0, "%s; rx-drop: %zd\n", __func__, count); return 0; } @@ -600,7 +601,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) netif_stop_queue(ndev); - IRDA_DEBUG(3, "%s(), skb->len = %d\n", __FUNCTION__, skb->len); + IRDA_DEBUG(3, "%s(), skb->len = %d\n", __func__, skb->len); speed = irda_get_next_speed(skb); if ((speed != dev->speed) && (speed != -1)) { @@ -637,7 +638,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) /* Check problems */ if(spin_is_locked(&dev->tx_lock)) { - IRDA_DEBUG(3, "%s(), write not completed\n", __FUNCTION__); + IRDA_DEBUG(3, "%s(), write not completed\n", __func__); } /* serialize with write completion */ @@ -666,7 +667,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) else if (unlikely(actual < 0)) { /* could be dropped later when we have tx_timeout to recover */ IRDA_ERROR("%s: drv->do_write failed (%d)\n", - __FUNCTION__, actual); + __func__, actual); dev_kfree_skb_any(skb); dev->stats.tx_errors++; dev->stats.tx_dropped++; @@ -687,7 +688,7 @@ static int sirdev_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) IRDA_ASSERT(dev != NULL, return -1;); - IRDA_DEBUG(3, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, ndev->name, cmd); + IRDA_DEBUG(3, "%s(), %s, (cmd=0x%X)\n", __func__, ndev->name, cmd); switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ @@ -804,7 +805,7 @@ static int sirdev_open(struct net_device *ndev) if (!try_module_get(drv->owner)) return -ESTALE; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); if (sirdev_alloc_buffers(dev)) goto errout_dec; @@ -822,7 +823,7 @@ static int sirdev_open(struct net_device *ndev) netif_wake_queue(ndev); - IRDA_DEBUG(2, "%s - done, speed = %d\n", __FUNCTION__, dev->speed); + IRDA_DEBUG(2, "%s - done, speed = %d\n", __func__, dev->speed); return 0; @@ -842,7 +843,7 @@ static int sirdev_close(struct net_device *ndev) struct sir_dev *dev = ndev->priv; const struct sir_driver *drv; -// IRDA_DEBUG(0, "%s\n", __FUNCTION__); +// IRDA_DEBUG(0, "%s\n", __func__); netif_stop_queue(ndev); @@ -878,7 +879,7 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n struct net_device *ndev; struct sir_dev *dev; - IRDA_DEBUG(0, "%s - %s\n", __FUNCTION__, name); + IRDA_DEBUG(0, "%s - %s\n", __func__, name); /* instead of adding tests to protect against drv->do_write==NULL * at several places we refuse to create a sir_dev instance for @@ -892,7 +893,7 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n */ ndev = alloc_irdadev(sizeof(*dev)); if (ndev == NULL) { - IRDA_ERROR("%s - Can't allocate memory for IrDA control block!\n", __FUNCTION__); + IRDA_ERROR("%s - Can't allocate memory for IrDA control block!\n", __func__); goto out; } dev = ndev->priv; @@ -921,7 +922,7 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n ndev->do_ioctl = sirdev_ioctl; if (register_netdev(ndev)) { - IRDA_ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); + IRDA_ERROR("%s(), register_netdev() failed!\n", __func__); goto out_freenetdev; } @@ -938,7 +939,7 @@ int sirdev_put_instance(struct sir_dev *dev) { int err = 0; - IRDA_DEBUG(0, "%s\n", __FUNCTION__); + IRDA_DEBUG(0, "%s\n", __func__); atomic_set(&dev->enable_rx, 0); @@ -948,7 +949,7 @@ int sirdev_put_instance(struct sir_dev *dev) if (dev->dongle_drv) err = sirdev_schedule_dongle_close(dev); if (err) - IRDA_ERROR("%s - error %d\n", __FUNCTION__, err); + IRDA_ERROR("%s - error %d\n", __func__, err); sirdev_close(dev->netdev); diff --git a/drivers/net/irda/sir_dongle.c b/drivers/net/irda/sir_dongle.c index 25d5b8a96bd..36030241f7a 100644 --- a/drivers/net/irda/sir_dongle.c +++ b/drivers/net/irda/sir_dongle.c @@ -36,7 +36,7 @@ int irda_register_dongle(struct dongle_driver *new) struct dongle_driver *drv; IRDA_DEBUG(0, "%s : registering dongle \"%s\" (%d).\n", - __FUNCTION__, new->driver_name, new->type); + __func__, new->driver_name, new->type); mutex_lock(&dongle_list_lock); list_for_each(entry, &dongle_list) { diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 78dc8e7837f..b5360fe99d3 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -460,7 +460,7 @@ static int __init smsc_ircc_init(void) { int ret; - IRDA_DEBUG(1, "%s\n", __FUNCTION__); + IRDA_DEBUG(1, "%s\n", __func__); ret = platform_driver_register(&smsc_ircc_driver); if (ret) { @@ -500,7 +500,7 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u struct net_device *dev; int err; - IRDA_DEBUG(1, "%s\n", __FUNCTION__); + IRDA_DEBUG(1, "%s\n", __func__); err = smsc_ircc_present(fir_base, sir_base); if (err) @@ -508,7 +508,7 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u err = -ENOMEM; if (dev_count >= ARRAY_SIZE(dev_self)) { - IRDA_WARNING("%s(), too many devices!\n", __FUNCTION__); + IRDA_WARNING("%s(), too many devices!\n", __func__); goto err_out1; } @@ -517,7 +517,7 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u */ dev = alloc_irdadev(sizeof(struct smsc_ircc_cb)); if (!dev) { - IRDA_WARNING("%s() can't allocate net device\n", __FUNCTION__); + IRDA_WARNING("%s() can't allocate net device\n", __func__); goto err_out1; } @@ -633,14 +633,14 @@ static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base) if (!request_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT, driver_name)) { IRDA_WARNING("%s: can't get fir_base of 0x%03x\n", - __FUNCTION__, fir_base); + __func__, fir_base); goto out1; } if (!request_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT, driver_name)) { IRDA_WARNING("%s: can't get sir_base of 0x%03x\n", - __FUNCTION__, sir_base); + __func__, sir_base); goto out2; } @@ -656,7 +656,7 @@ static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base) if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) { IRDA_WARNING("%s(), addr 0x%04x - no device found!\n", - __FUNCTION__, fir_base); + __func__, fir_base); goto out3; } IRDA_MESSAGE("SMsC IrDA Controller found\n IrCC version %d.%d, " @@ -793,7 +793,7 @@ static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd IRDA_ASSERT(self != NULL, return -1;); - IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd); + IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ @@ -878,7 +878,7 @@ int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) unsigned long flags; s32 speed; - IRDA_DEBUG(1, "%s\n", __FUNCTION__); + IRDA_DEBUG(1, "%s\n", __func__); IRDA_ASSERT(dev != NULL, return 0;); @@ -953,21 +953,21 @@ static void smsc_ircc_set_fir_speed(struct smsc_ircc_cb *self, u32 speed) ir_mode = IRCC_CFGA_IRDA_HDLC; ctrl = IRCC_CRC; fast = 0; - IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __func__); break; case 1152000: ir_mode = IRCC_CFGA_IRDA_HDLC; ctrl = IRCC_1152 | IRCC_CRC; fast = IRCC_LCR_A_FAST | IRCC_LCR_A_GP_DATA; IRDA_DEBUG(0, "%s(), handling baud of 1152000\n", - __FUNCTION__); + __func__); break; case 4000000: ir_mode = IRCC_CFGA_IRDA_4PPM; ctrl = IRCC_CRC; fast = IRCC_LCR_A_FAST; IRDA_DEBUG(0, "%s(), handling baud of 4000000\n", - __FUNCTION__); + __func__); break; } #if 0 @@ -995,7 +995,7 @@ static void smsc_ircc_fir_start(struct smsc_ircc_cb *self) struct net_device *dev; int fir_base; - IRDA_DEBUG(1, "%s\n", __FUNCTION__); + IRDA_DEBUG(1, "%s\n", __func__); IRDA_ASSERT(self != NULL, return;); dev = self->netdev; @@ -1043,7 +1043,7 @@ static void smsc_ircc_fir_stop(struct smsc_ircc_cb *self) { int fir_base; - IRDA_DEBUG(1, "%s\n", __FUNCTION__); + IRDA_DEBUG(1, "%s\n", __func__); IRDA_ASSERT(self != NULL, return;); @@ -1067,7 +1067,7 @@ static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed) struct net_device *dev; int last_speed_was_sir; - IRDA_DEBUG(0, "%s() changing speed to: %d\n", __FUNCTION__, speed); + IRDA_DEBUG(0, "%s() changing speed to: %d\n", __func__, speed); IRDA_ASSERT(self != NULL, return;); dev = self->netdev; @@ -1135,7 +1135,7 @@ void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, __u32 speed) int lcr; /* Line control reg */ int divisor; - IRDA_DEBUG(0, "%s(), Setting speed to: %d\n", __FUNCTION__, speed); + IRDA_DEBUG(0, "%s(), Setting speed to: %d\n", __func__, speed); IRDA_ASSERT(self != NULL, return;); iobase = self->io.sir_base; @@ -1170,7 +1170,7 @@ void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, __u32 speed) /* Turn on interrups */ outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); - IRDA_DEBUG(2, "%s() speed changed to: %d\n", __FUNCTION__, speed); + IRDA_DEBUG(2, "%s() speed changed to: %d\n", __func__, speed); } @@ -1253,7 +1253,7 @@ static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs) int iobase = self->io.fir_base; u8 ctrl; - IRDA_DEBUG(3, "%s\n", __FUNCTION__); + IRDA_DEBUG(3, "%s\n", __func__); #if 1 /* Disable Rx */ register_bank(iobase, 0); @@ -1307,7 +1307,7 @@ static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self) { int iobase = self->io.fir_base; - IRDA_DEBUG(3, "%s\n", __FUNCTION__); + IRDA_DEBUG(3, "%s\n", __func__); #if 0 /* Disable Tx */ register_bank(iobase, 0); @@ -1411,7 +1411,7 @@ static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self) register_bank(iobase, 0); - IRDA_DEBUG(3, "%s\n", __FUNCTION__); + IRDA_DEBUG(3, "%s\n", __func__); #if 0 /* Disable Rx */ register_bank(iobase, 0); @@ -1422,7 +1422,7 @@ static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self) lsr= inb(iobase + IRCC_LSR); msgcnt = inb(iobase + IRCC_LCR_B) & 0x08; - IRDA_DEBUG(2, "%s: dma count = %d\n", __FUNCTION__, + IRDA_DEBUG(2, "%s: dma count = %d\n", __func__, get_dma_residue(self->io.dma)); len = self->rx_buff.truesize - get_dma_residue(self->io.dma); @@ -1445,15 +1445,15 @@ static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self) len -= self->io.speed < 4000000 ? 2 : 4; if (len < 2 || len > 2050) { - IRDA_WARNING("%s(), bogus len=%d\n", __FUNCTION__, len); + IRDA_WARNING("%s(), bogus len=%d\n", __func__, len); return; } - IRDA_DEBUG(2, "%s: msgcnt = %d, len=%d\n", __FUNCTION__, msgcnt, len); + IRDA_DEBUG(2, "%s: msgcnt = %d, len=%d\n", __func__, msgcnt, len); skb = dev_alloc_skb(len + 1); if (!skb) { IRDA_WARNING("%s(), memory squeeze, dropping frame.\n", - __FUNCTION__); + __func__); return; } /* Make sure IP header gets aligned */ @@ -1494,7 +1494,7 @@ static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self) /* Make sure we don't stay here to long */ if (boguscount++ > 32) { - IRDA_DEBUG(2, "%s(), breaking!\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), breaking!\n", __func__); break; } } while (inb(iobase + UART_LSR) & UART_LSR_DR); @@ -1536,7 +1536,7 @@ static irqreturn_t smsc_ircc_interrupt(int dummy, void *dev_id) lcra = inb(iobase + IRCC_LCR_A); lsr = inb(iobase + IRCC_LSR); - IRDA_DEBUG(2, "%s(), iir = 0x%02x\n", __FUNCTION__, iir); + IRDA_DEBUG(2, "%s(), iir = 0x%02x\n", __func__, iir); if (iir & IRCC_IIR_EOM) { if (self->io.direction == IO_RECV) @@ -1548,7 +1548,7 @@ static irqreturn_t smsc_ircc_interrupt(int dummy, void *dev_id) } if (iir & IRCC_IIR_ACTIVE_FRAME) { - /*printk(KERN_WARNING "%s(): Active Frame\n", __FUNCTION__);*/ + /*printk(KERN_WARNING "%s(): Active Frame\n", __func__);*/ } /* Enable interrupts again */ @@ -1587,11 +1587,11 @@ static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev) lsr = inb(iobase + UART_LSR); IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", - __FUNCTION__, iir, lsr, iobase); + __func__, iir, lsr, iobase); switch (iir) { case UART_IIR_RLSI: - IRDA_DEBUG(2, "%s(), RLSI\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), RLSI\n", __func__); break; case UART_IIR_RDI: /* Receive interrupt */ @@ -1604,7 +1604,7 @@ static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev) break; default: IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n", - __FUNCTION__, iir); + __func__, iir); break; } @@ -1631,11 +1631,11 @@ static int ircc_is_receiving(struct smsc_ircc_cb *self) int status = FALSE; /* int iobase; */ - IRDA_DEBUG(1, "%s\n", __FUNCTION__); + IRDA_DEBUG(1, "%s\n", __func__); IRDA_ASSERT(self != NULL, return FALSE;); - IRDA_DEBUG(0, "%s: dma count = %d\n", __FUNCTION__, + IRDA_DEBUG(0, "%s: dma count = %d\n", __func__, get_dma_residue(self->io.dma)); status = (self->rx_buff.state != OUTSIDE_FRAME); @@ -1652,7 +1652,7 @@ static int smsc_ircc_request_irq(struct smsc_ircc_cb *self) self->netdev->name, self->netdev); if (error) IRDA_DEBUG(0, "%s(), unable to allocate irq=%d, err=%d\n", - __FUNCTION__, self->io.irq, error); + __func__, self->io.irq, error); return error; } @@ -1696,21 +1696,21 @@ static int smsc_ircc_net_open(struct net_device *dev) struct smsc_ircc_cb *self; char hwname[16]; - IRDA_DEBUG(1, "%s\n", __FUNCTION__); + IRDA_DEBUG(1, "%s\n", __func__); IRDA_ASSERT(dev != NULL, return -1;); self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); if (self->io.suspended) { - IRDA_DEBUG(0, "%s(), device is suspended\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), device is suspended\n", __func__); return -EAGAIN; } if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name, (void *) dev)) { IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n", - __FUNCTION__, self->io.irq); + __func__, self->io.irq); return -EAGAIN; } @@ -1734,7 +1734,7 @@ static int smsc_ircc_net_open(struct net_device *dev) smsc_ircc_net_close(dev); IRDA_WARNING("%s(), unable to allocate DMA=%d\n", - __FUNCTION__, self->io.dma); + __func__, self->io.dma); return -EAGAIN; } @@ -1753,7 +1753,7 @@ static int smsc_ircc_net_close(struct net_device *dev) { struct smsc_ircc_cb *self; - IRDA_DEBUG(1, "%s\n", __FUNCTION__); + IRDA_DEBUG(1, "%s\n", __func__); IRDA_ASSERT(dev != NULL, return -1;); self = netdev_priv(dev); @@ -1836,7 +1836,7 @@ static int smsc_ircc_resume(struct platform_device *dev) */ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self) { - IRDA_DEBUG(1, "%s\n", __FUNCTION__); + IRDA_DEBUG(1, "%s\n", __func__); IRDA_ASSERT(self != NULL, return -1;); @@ -1848,12 +1848,12 @@ static int __exit smsc_ircc_close(struct smsc_ircc_cb *self) smsc_ircc_stop_interrupts(self); /* Release the PORTS that this driver is using */ - IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__, + IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __func__, self->io.fir_base); release_region(self->io.fir_base, self->io.fir_ext); - IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__, + IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __func__, self->io.sir_base); release_region(self->io.sir_base, self->io.sir_ext); @@ -1875,7 +1875,7 @@ static void __exit smsc_ircc_cleanup(void) { int i; - IRDA_DEBUG(1, "%s\n", __FUNCTION__); + IRDA_DEBUG(1, "%s\n", __func__); for (i = 0; i < 2; i++) { if (dev_self[i]) @@ -1899,7 +1899,7 @@ void smsc_ircc_sir_start(struct smsc_ircc_cb *self) struct net_device *dev; int fir_base, sir_base; - IRDA_DEBUG(3, "%s\n", __FUNCTION__); + IRDA_DEBUG(3, "%s\n", __func__); IRDA_ASSERT(self != NULL, return;); dev = self->netdev; @@ -1926,7 +1926,7 @@ void smsc_ircc_sir_start(struct smsc_ircc_cb *self) /* Turn on interrups */ outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, sir_base + UART_IER); - IRDA_DEBUG(3, "%s() - exit\n", __FUNCTION__); + IRDA_DEBUG(3, "%s() - exit\n", __func__); outb(0x00, fir_base + IRCC_MASTER); } @@ -1936,7 +1936,7 @@ void smsc_ircc_sir_stop(struct smsc_ircc_cb *self) { int iobase; - IRDA_DEBUG(3, "%s\n", __FUNCTION__); + IRDA_DEBUG(3, "%s\n", __func__); iobase = self->io.sir_base; /* Reset UART */ @@ -1962,7 +1962,7 @@ static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self) IRDA_ASSERT(self != NULL, return;); - IRDA_DEBUG(4, "%s\n", __FUNCTION__); + IRDA_DEBUG(4, "%s\n", __func__); iobase = self->io.sir_base; @@ -1984,7 +1984,7 @@ static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self) */ if (self->new_speed) { IRDA_DEBUG(5, "%s(), Changing speed to %d.\n", - __FUNCTION__, self->new_speed); + __func__, self->new_speed); smsc_ircc_sir_wait_hw_transmitter_finish(self); smsc_ircc_change_speed(self, self->new_speed); self->new_speed = 0; @@ -2023,7 +2023,7 @@ static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len) /* Tx FIFO should be empty! */ if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) { - IRDA_WARNING("%s(), failed, fifo not empty!\n", __FUNCTION__); + IRDA_WARNING("%s(), failed, fifo not empty!\n", __func__); return 0; } @@ -2123,7 +2123,7 @@ static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self) udelay(1); if (count == 0) - IRDA_DEBUG(0, "%s(): stuck transmitter\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(): stuck transmitter\n", __func__); } @@ -2145,7 +2145,7 @@ static int __init smsc_ircc_look_for_chips(void) while (address->cfg_base) { cfg_base = address->cfg_base; - /*printk(KERN_WARNING "%s(): probing: 0x%02x for: 0x%02x\n", __FUNCTION__, cfg_base, address->type);*/ + /*printk(KERN_WARNING "%s(): probing: 0x%02x for: 0x%02x\n", __func__, cfg_base, address->type);*/ if (address->type & SMSCSIO_TYPE_FDC) { type = "FDC"; @@ -2184,7 +2184,7 @@ static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned shor u8 mode, dma, irq; int ret = -ENODEV; - IRDA_DEBUG(1, "%s\n", __FUNCTION__); + IRDA_DEBUG(1, "%s\n", __func__); if (smsc_ircc_probe(cfgbase, SMSCSIOFLAT_DEVICEID_REG, chips, type) == NULL) return ret; @@ -2192,10 +2192,10 @@ static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned shor outb(SMSCSIOFLAT_UARTMODE0C_REG, cfgbase); mode = inb(cfgbase + 1); - /*printk(KERN_WARNING "%s(): mode: 0x%02x\n", __FUNCTION__, mode);*/ + /*printk(KERN_WARNING "%s(): mode: 0x%02x\n", __func__, mode);*/ if (!(mode & SMSCSIOFLAT_UART2MODE_VAL_IRDA)) - IRDA_WARNING("%s(): IrDA not enabled\n", __FUNCTION__); + IRDA_WARNING("%s(): IrDA not enabled\n", __func__); outb(SMSCSIOFLAT_UART2BASEADDR_REG, cfgbase); sirbase = inb(cfgbase + 1) << 2; @@ -2212,7 +2212,7 @@ static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned shor outb(SMSCSIOFLAT_UARTIRQSELECT_REG, cfgbase); irq = inb(cfgbase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK; - IRDA_MESSAGE("%s(): fir: 0x%02x, sir: 0x%02x, dma: %02d, irq: %d, mode: 0x%02x\n", __FUNCTION__, firbase, sirbase, dma, irq, mode); + IRDA_MESSAGE("%s(): fir: 0x%02x, sir: 0x%02x, dma: %02d, irq: %d, mode: 0x%02x\n", __func__, firbase, sirbase, dma, irq, mode); if (firbase && smsc_ircc_open(firbase, sirbase, dma, irq) == 0) ret = 0; @@ -2234,7 +2234,7 @@ static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned sho unsigned short fir_io, sir_io; int ret = -ENODEV; - IRDA_DEBUG(1, "%s\n", __FUNCTION__); + IRDA_DEBUG(1, "%s\n", __func__); if (smsc_ircc_probe(cfg_base, 0x20, chips, type) == NULL) return ret; @@ -2268,7 +2268,7 @@ static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned sho static int __init smsc_access(unsigned short cfg_base, unsigned char reg) { - IRDA_DEBUG(1, "%s\n", __FUNCTION__); + IRDA_DEBUG(1, "%s\n", __func__); outb(reg, cfg_base); return inb(cfg_base) != reg ? -1 : 0; @@ -2278,7 +2278,7 @@ static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, { u8 devid, xdevid, rev; - IRDA_DEBUG(1, "%s\n", __FUNCTION__); + IRDA_DEBUG(1, "%s\n", __func__); /* Leave configuration */ @@ -2353,7 +2353,7 @@ static int __init smsc_superio_fdc(unsigned short cfg_base) if (!request_region(cfg_base, 2, driver_name)) { IRDA_WARNING("%s: can't get cfg_base of 0x%03x\n", - __FUNCTION__, cfg_base); + __func__, cfg_base); } else { if (!smsc_superio_flat(fdc_chips_flat, cfg_base, "FDC") || !smsc_superio_paged(fdc_chips_paged, cfg_base, "FDC")) @@ -2371,7 +2371,7 @@ static int __init smsc_superio_lpc(unsigned short cfg_base) if (!request_region(cfg_base, 2, driver_name)) { IRDA_WARNING("%s: can't get cfg_base of 0x%03x\n", - __FUNCTION__, cfg_base); + __func__, cfg_base); } else { if (!smsc_superio_flat(lpc_chips_flat, cfg_base, "LPC") || !smsc_superio_paged(lpc_chips_paged, cfg_base, "LPC")) @@ -2932,7 +2932,7 @@ static void smsc_ircc_set_transceiver_smsc_ircc_atc(int fir_base, u32 speed) /* empty */; if (val) - IRDA_WARNING("%s(): ATC: 0x%02x\n", __FUNCTION__, + IRDA_WARNING("%s(): ATC: 0x%02x\n", __func__, inb(fir_base + IRCC_ATC)); } diff --git a/drivers/net/irda/tekram-sir.c b/drivers/net/irda/tekram-sir.c index d1ce5ae6a17..048a1542284 100644 --- a/drivers/net/irda/tekram-sir.c +++ b/drivers/net/irda/tekram-sir.c @@ -77,7 +77,7 @@ static int tekram_open(struct sir_dev *dev) { struct qos_info *qos = &dev->qos; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); sirdev_set_dtr_rts(dev, TRUE, TRUE); @@ -92,7 +92,7 @@ static int tekram_open(struct sir_dev *dev) static int tekram_close(struct sir_dev *dev) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* Power off dongle */ sirdev_set_dtr_rts(dev, FALSE, FALSE); @@ -130,7 +130,7 @@ static int tekram_change_speed(struct sir_dev *dev, unsigned speed) u8 byte; static int ret = 0; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); switch(state) { case SIRDEV_STATE_DONGLE_SPEED: @@ -179,7 +179,7 @@ static int tekram_change_speed(struct sir_dev *dev, unsigned speed) break; default: - IRDA_ERROR("%s - undefined state %d\n", __FUNCTION__, state); + IRDA_ERROR("%s - undefined state %d\n", __func__, state); ret = -EINVAL; break; } @@ -204,7 +204,7 @@ static int tekram_change_speed(struct sir_dev *dev, unsigned speed) static int tekram_reset(struct sir_dev *dev) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* Clear DTR, Set RTS */ sirdev_set_dtr_rts(dev, FALSE, TRUE); diff --git a/drivers/net/irda/toim3232-sir.c b/drivers/net/irda/toim3232-sir.c index aa1a9b0ed83..fcf287b749d 100644 --- a/drivers/net/irda/toim3232-sir.c +++ b/drivers/net/irda/toim3232-sir.c @@ -181,7 +181,7 @@ static int toim3232_open(struct sir_dev *dev) { struct qos_info *qos = &dev->qos; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* Pull the lines high to start with. * @@ -209,7 +209,7 @@ static int toim3232_open(struct sir_dev *dev) static int toim3232_close(struct sir_dev *dev) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* Power off dongle */ sirdev_set_dtr_rts(dev, FALSE, FALSE); @@ -241,7 +241,7 @@ static int toim3232_change_speed(struct sir_dev *dev, unsigned speed) u8 byte; static int ret = 0; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); switch(state) { case SIRDEV_STATE_DONGLE_SPEED: @@ -299,7 +299,7 @@ static int toim3232_change_speed(struct sir_dev *dev, unsigned speed) break; default: - printk(KERN_ERR "%s - undefined state %d\n", __FUNCTION__, state); + printk(KERN_ERR "%s - undefined state %d\n", __func__, state); ret = -EINVAL; break; } @@ -344,7 +344,7 @@ static int toim3232_change_speed(struct sir_dev *dev, unsigned speed) static int toim3232_reset(struct sir_dev *dev) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* Switch off both DTR and RTS to switch off dongle */ sirdev_set_dtr_rts(dev, FALSE, FALSE); diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 04ad3573b15..84e609ea5fb 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -152,12 +152,12 @@ static int __init via_ircc_init(void) { int rc; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); rc = pci_register_driver(&via_driver); if (rc < 0) { IRDA_DEBUG(0, "%s(): error rc = %d, returning -ENODEV...\n", - __FUNCTION__, rc); + __func__, rc); return -ENODEV; } return 0; @@ -170,11 +170,11 @@ static int __devinit via_init_one (struct pci_dev *pcidev, const struct pci_devi u16 Chipset,FirDRQ1,FirDRQ0,FirIRQ,FirIOBase; chipio_t info; - IRDA_DEBUG(2, "%s(): Device ID=(0X%X)\n", __FUNCTION__, id->device); + IRDA_DEBUG(2, "%s(): Device ID=(0X%X)\n", __func__, id->device); rc = pci_enable_device (pcidev); if (rc) { - IRDA_DEBUG(0, "%s(): error rc = %d\n", __FUNCTION__, rc); + IRDA_DEBUG(0, "%s(): error rc = %d\n", __func__, rc); return -ENODEV; } @@ -185,7 +185,7 @@ static int __devinit via_init_one (struct pci_dev *pcidev, const struct pci_devi Chipset=0x3076; if (Chipset==0x3076) { - IRDA_DEBUG(2, "%s(): Chipset = 3076\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(): Chipset = 3076\n", __func__); WriteLPCReg(7,0x0c ); temp=ReadLPCReg(0x30);//check if BIOS Enable Fir @@ -222,7 +222,7 @@ static int __devinit via_init_one (struct pci_dev *pcidev, const struct pci_devi } else rc = -ENODEV; //IR not turn on } else { //Not VT1211 - IRDA_DEBUG(2, "%s(): Chipset = 3096\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(): Chipset = 3096\n", __func__); pci_read_config_byte(pcidev,0x67,&bTmp);//check if BIOS Enable Fir if((bTmp&0x01)==1) { // BIOS enable FIR @@ -262,7 +262,7 @@ static int __devinit via_init_one (struct pci_dev *pcidev, const struct pci_devi rc = -ENODEV; //IR not turn on !!!!! }//Not VT1211 - IRDA_DEBUG(2, "%s(): End - rc = %d\n", __FUNCTION__, rc); + IRDA_DEBUG(2, "%s(): End - rc = %d\n", __func__, rc); return rc; } @@ -276,7 +276,7 @@ static void via_ircc_clean(void) { int i; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); for (i=0; i < ARRAY_SIZE(dev_self); i++) { if (dev_self[i]) @@ -286,7 +286,7 @@ static void via_ircc_clean(void) static void __devexit via_remove_one (struct pci_dev *pdev) { - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); /* FIXME : This is ugly. We should use pci_get_drvdata(pdev); * to get our driver instance and call directly via_ircc_close(). @@ -301,7 +301,7 @@ static void __devexit via_remove_one (struct pci_dev *pdev) static void __exit via_ircc_cleanup(void) { - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); /* FIXME : This should be redundant, as pci_unregister_driver() * should call via_remove_one() on each device. @@ -324,7 +324,7 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) struct via_ircc_cb *self; int err; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); if (i >= ARRAY_SIZE(dev_self)) return -ENOMEM; @@ -360,7 +360,7 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) /* Reserve the ioports that we need */ if (!request_region(self->io.fir_base, self->io.fir_ext, driver_name)) { IRDA_DEBUG(0, "%s(), can't get iobase of 0x%03x\n", - __FUNCTION__, self->io.fir_base); + __func__, self->io.fir_base); err = -ENODEV; goto err_out1; } @@ -471,7 +471,7 @@ static int via_ircc_close(struct via_ircc_cb *self) { int iobase; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return -1;); @@ -483,7 +483,7 @@ static int via_ircc_close(struct via_ircc_cb *self) /* Release the PORT that this driver is using */ IRDA_DEBUG(2, "%s(), Releasing Region %03x\n", - __FUNCTION__, self->io.fir_base); + __func__, self->io.fir_base); release_region(self->io.fir_base, self->io.fir_ext); if (self->tx_buff.head) dma_free_coherent(NULL, self->tx_buff.truesize, @@ -509,7 +509,7 @@ static void via_hw_init(struct via_ircc_cb *self) { int iobase = self->io.fir_base; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); SetMaxRxPacketSize(iobase, 0x0fff); //set to max:4095 // FIFO Init @@ -582,7 +582,7 @@ static void via_ircc_change_dongle_speed(int iobase, int speed, speed = speed; IRDA_DEBUG(1, "%s(): change_dongle_speed to %d for 0x%x, %d\n", - __FUNCTION__, speed, iobase, dongle_id); + __func__, speed, iobase, dongle_id); switch (dongle_id) { @@ -671,7 +671,7 @@ static void via_ircc_change_dongle_speed(int iobase, int speed, case 0x11: /* Temic TFDS4500 */ - IRDA_DEBUG(2, "%s: Temic TFDS4500: One RX pin, TX normal, RX inverted.\n", __FUNCTION__); + IRDA_DEBUG(2, "%s: Temic TFDS4500: One RX pin, TX normal, RX inverted.\n", __func__); UseOneRX(iobase, ON); //use ONE RX....RX1 InvertTX(iobase, OFF); @@ -689,7 +689,7 @@ static void via_ircc_change_dongle_speed(int iobase, int speed, SlowIRRXLowActive(iobase, OFF); } else{ - IRDA_DEBUG(0, "%s: Warning: TFDS4500 not running in SIR mode !\n", __FUNCTION__); + IRDA_DEBUG(0, "%s: Warning: TFDS4500 not running in SIR mode !\n", __func__); } break; @@ -707,7 +707,7 @@ static void via_ircc_change_dongle_speed(int iobase, int speed, default: IRDA_ERROR("%s: Error: dongle_id %d unsupported !\n", - __FUNCTION__, dongle_id); + __func__, dongle_id); } } @@ -726,7 +726,7 @@ static void via_ircc_change_speed(struct via_ircc_cb *self, __u32 speed) iobase = self->io.fir_base; /* Update accounting for new speed */ self->io.speed = speed; - IRDA_DEBUG(1, "%s: change_speed to %d bps.\n", __FUNCTION__, speed); + IRDA_DEBUG(1, "%s: change_speed to %d bps.\n", __func__, speed); WriteReg(iobase, I_ST_CT_0, 0x0); @@ -957,7 +957,7 @@ static int via_ircc_dma_xmit(struct via_ircc_cb *self, u16 iobase) self->tx_buff.head) + self->tx_buff_dma, self->tx_fifo.queue[self->tx_fifo.ptr].len, DMA_TX_MODE); IRDA_DEBUG(1, "%s: tx_fifo.ptr=%x,len=%x,tx_fifo.len=%x..\n", - __FUNCTION__, self->tx_fifo.ptr, + __func__, self->tx_fifo.ptr, self->tx_fifo.queue[self->tx_fifo.ptr].len, self->tx_fifo.len); @@ -981,7 +981,7 @@ static int via_ircc_dma_xmit_complete(struct via_ircc_cb *self) int ret = TRUE; u8 Tx_status; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); iobase = self->io.fir_base; /* Disable DMA */ @@ -1014,7 +1014,7 @@ static int via_ircc_dma_xmit_complete(struct via_ircc_cb *self) } IRDA_DEBUG(1, "%s: tx_fifo.len=%x ,tx_fifo.ptr=%x,tx_fifo.free=%x...\n", - __FUNCTION__, + __func__, self->tx_fifo.len, self->tx_fifo.ptr, self->tx_fifo.free); /* F01_S // Any frames to be sent back-to-back? @@ -1050,7 +1050,7 @@ static int via_ircc_dma_receive(struct via_ircc_cb *self) iobase = self->io.fir_base; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; self->tx_fifo.tail = self->tx_buff.head; @@ -1134,13 +1134,13 @@ static int via_ircc_dma_receive_complete(struct via_ircc_cb *self, return TRUE; //interrupt only, data maybe move by RxT if (((len - 4) < 2) || ((len - 4) > 2048)) { IRDA_DEBUG(1, "%s(): Trouble:len=%x,CurCount=%x,LastCount=%x..\n", - __FUNCTION__, len, RxCurCount(iobase, self), + __func__, len, RxCurCount(iobase, self), self->RxLastCount); hwreset(self); return FALSE; } IRDA_DEBUG(2, "%s(): fifo.len=%x,len=%x,CurCount=%x..\n", - __FUNCTION__, + __func__, st_fifo->len, len - 4, RxCurCount(iobase, self)); st_fifo->entries[st_fifo->tail].status = status; @@ -1187,7 +1187,7 @@ F01_E */ skb_put(skb, len - 4); skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4); - IRDA_DEBUG(2, "%s(): len=%x.rx_buff=%p\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(): len=%x.rx_buff=%p\n", __func__, len - 4, self->rx_buff.data); // Move to next frame @@ -1217,7 +1217,7 @@ static int upload_rxdata(struct via_ircc_cb *self, int iobase) len = GetRecvByte(iobase, self); - IRDA_DEBUG(2, "%s(): len=%x\n", __FUNCTION__, len); + IRDA_DEBUG(2, "%s(): len=%x\n", __func__, len); if ((len - 4) < 2) { self->stats.rx_dropped++; @@ -1302,7 +1302,7 @@ static int RxTimerHandler(struct via_ircc_cb *self, int iobase) skb_put(skb, len - 4); skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4); - IRDA_DEBUG(2, "%s(): len=%x.head=%x\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(): len=%x.head=%x\n", __func__, len - 4, st_fifo->head); // Move to next frame @@ -1318,7 +1318,7 @@ static int RxTimerHandler(struct via_ircc_cb *self, int iobase) IRDA_DEBUG(2, "%s(): End of upload HostStatus=%x,RxStatus=%x\n", - __FUNCTION__, + __func__, GetHostStatus(iobase), GetRXStatus(iobase)); /* @@ -1358,7 +1358,7 @@ static irqreturn_t via_ircc_interrupt(int dummy, void *dev_id) iHostIntType = GetHostStatus(iobase); IRDA_DEBUG(4, "%s(): iHostIntType %02x: %s %s %s %02x\n", - __FUNCTION__, iHostIntType, + __func__, iHostIntType, (iHostIntType & 0x40) ? "Timer" : "", (iHostIntType & 0x20) ? "Tx" : "", (iHostIntType & 0x10) ? "Rx" : "", @@ -1388,7 +1388,7 @@ static irqreturn_t via_ircc_interrupt(int dummy, void *dev_id) iTxIntType = GetTXStatus(iobase); IRDA_DEBUG(4, "%s(): iTxIntType %02x: %s %s %s %s\n", - __FUNCTION__, iTxIntType, + __func__, iTxIntType, (iTxIntType & 0x08) ? "FIFO underr." : "", (iTxIntType & 0x04) ? "EOM" : "", (iTxIntType & 0x02) ? "FIFO ready" : "", @@ -1412,7 +1412,7 @@ static irqreturn_t via_ircc_interrupt(int dummy, void *dev_id) iRxIntType = GetRXStatus(iobase); IRDA_DEBUG(4, "%s(): iRxIntType %02x: %s %s %s %s %s %s %s\n", - __FUNCTION__, iRxIntType, + __func__, iRxIntType, (iRxIntType & 0x80) ? "PHY err." : "", (iRxIntType & 0x40) ? "CRC err" : "", (iRxIntType & 0x20) ? "FIFO overr." : "", @@ -1421,7 +1421,7 @@ static irqreturn_t via_ircc_interrupt(int dummy, void *dev_id) (iRxIntType & 0x02) ? "RxMaxLen" : "", (iRxIntType & 0x01) ? "SIR bad" : ""); if (!iRxIntType) - IRDA_DEBUG(3, "%s(): RxIRQ =0\n", __FUNCTION__); + IRDA_DEBUG(3, "%s(): RxIRQ =0\n", __func__); if (iRxIntType & 0x10) { if (via_ircc_dma_receive_complete(self, iobase)) { @@ -1431,7 +1431,7 @@ static irqreturn_t via_ircc_interrupt(int dummy, void *dev_id) } // No ERR else { //ERR IRDA_DEBUG(4, "%s(): RxIRQ ERR:iRxIntType=%x,HostIntType=%x,CurCount=%x,RxLastCount=%x_____\n", - __FUNCTION__, iRxIntType, iHostIntType, + __func__, iRxIntType, iHostIntType, RxCurCount(iobase, self), self->RxLastCount); @@ -1456,7 +1456,7 @@ static void hwreset(struct via_ircc_cb *self) int iobase; iobase = self->io.fir_base; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); ResetChip(iobase, 5); EnableDMA(iobase, OFF); @@ -1501,7 +1501,7 @@ static int via_ircc_is_receiving(struct via_ircc_cb *self) if (CkRxRecv(iobase, self)) status = TRUE; - IRDA_DEBUG(2, "%s(): status=%x....\n", __FUNCTION__, status); + IRDA_DEBUG(2, "%s(): status=%x....\n", __func__, status); return status; } @@ -1519,7 +1519,7 @@ static int via_ircc_net_open(struct net_device *dev) int iobase; char hwname[32]; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); IRDA_ASSERT(dev != NULL, return -1;); self = (struct via_ircc_cb *) dev->priv; @@ -1586,7 +1586,7 @@ static int via_ircc_net_close(struct net_device *dev) struct via_ircc_cb *self; int iobase; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); IRDA_ASSERT(dev != NULL, return -1;); self = (struct via_ircc_cb *) dev->priv; @@ -1630,7 +1630,7 @@ static int via_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, IRDA_ASSERT(dev != NULL, return -1;); self = dev->priv; IRDA_ASSERT(self != NULL, return -1;); - IRDA_DEBUG(1, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, + IRDA_DEBUG(1, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); /* Disable interrupts & save flags */ spin_lock_irqsave(&self->lock, flags); diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index d15e00b8591..18f4b3a96ae 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -140,15 +140,15 @@ static void vlsi_ring_debug(struct vlsi_ring *r) unsigned i; printk(KERN_DEBUG "%s - ring %p / size %u / mask 0x%04x / len %u / dir %d / hw %p\n", - __FUNCTION__, r, r->size, r->mask, r->len, r->dir, r->rd[0].hw); - printk(KERN_DEBUG "%s - head = %d / tail = %d\n", __FUNCTION__, + __func__, r, r->size, r->mask, r->len, r->dir, r->rd[0].hw); + printk(KERN_DEBUG "%s - head = %d / tail = %d\n", __func__, atomic_read(&r->head) & r->mask, atomic_read(&r->tail) & r->mask); for (i = 0; i < r->size; i++) { rd = &r->rd[i]; - printk(KERN_DEBUG "%s - ring descr %u: ", __FUNCTION__, i); + printk(KERN_DEBUG "%s - ring descr %u: ", __func__, i); printk("skb=%p data=%p hw=%p\n", rd->skb, rd->buf, rd->hw); printk(KERN_DEBUG "%s - hw: status=%02x count=%u addr=0x%08x\n", - __FUNCTION__, (unsigned) rd_get_status(rd), + __func__, (unsigned) rd_get_status(rd), (unsigned) rd_get_count(rd), (unsigned) rd_get_addr(rd)); } } @@ -435,7 +435,7 @@ static struct vlsi_ring *vlsi_alloc_ring(struct pci_dev *pdev, struct ring_descr || !(busaddr = pci_map_single(pdev, rd->buf, len, dir))) { if (rd->buf) { IRDA_ERROR("%s: failed to create PCI-MAP for %p", - __FUNCTION__, rd->buf); + __func__, rd->buf); kfree(rd->buf); rd->buf = NULL; } @@ -489,7 +489,7 @@ static int vlsi_create_hwif(vlsi_irda_dev_t *idev) ringarea = pci_alloc_consistent(idev->pdev, HW_RING_AREA_SIZE, &idev->busaddr); if (!ringarea) { IRDA_ERROR("%s: insufficient memory for descriptor rings\n", - __FUNCTION__); + __func__); goto out; } memset(ringarea, 0, HW_RING_AREA_SIZE); @@ -564,7 +564,7 @@ static int vlsi_process_rx(struct vlsi_ring *r, struct ring_descr *rd) crclen = (idev->mode==IFF_FIR) ? sizeof(u32) : sizeof(u16); len -= crclen; /* remove trailing CRC */ if (len <= 0) { - IRDA_DEBUG(0, "%s: strange frame (len=%d)\n", __FUNCTION__, len); + IRDA_DEBUG(0, "%s: strange frame (len=%d)\n", __func__, len); ret |= VLSI_RX_DROP; goto done; } @@ -579,14 +579,14 @@ static int vlsi_process_rx(struct vlsi_ring *r, struct ring_descr *rd) */ le16_to_cpus(rd->buf+len); if (irda_calc_crc16(INIT_FCS,rd->buf,len+crclen) != GOOD_FCS) { - IRDA_DEBUG(0, "%s: crc error\n", __FUNCTION__); + IRDA_DEBUG(0, "%s: crc error\n", __func__); ret |= VLSI_RX_CRC; goto done; } } if (!rd->skb) { - IRDA_WARNING("%s: rx packet lost\n", __FUNCTION__); + IRDA_WARNING("%s: rx packet lost\n", __func__); ret |= VLSI_RX_DROP; goto done; } @@ -617,7 +617,7 @@ static void vlsi_fill_rx(struct vlsi_ring *r) for (rd = ring_last(r); rd != NULL; rd = ring_put(r)) { if (rd_is_active(rd)) { IRDA_WARNING("%s: driver bug: rx descr race with hw\n", - __FUNCTION__); + __func__); vlsi_ring_debug(r); break; } @@ -676,7 +676,7 @@ static void vlsi_rx_interrupt(struct net_device *ndev) if (ring_first(r) == NULL) { /* we are in big trouble, if this should ever happen */ - IRDA_ERROR("%s: rx ring exhausted!\n", __FUNCTION__); + IRDA_ERROR("%s: rx ring exhausted!\n", __func__); vlsi_ring_debug(r); } else @@ -697,7 +697,7 @@ static void vlsi_unarm_rx(vlsi_irda_dev_t *idev) if (rd_is_active(rd)) { rd_set_status(rd, 0); if (rd_get_count(rd)) { - IRDA_DEBUG(0, "%s - dropping rx packet\n", __FUNCTION__); + IRDA_DEBUG(0, "%s - dropping rx packet\n", __func__); ret = -VLSI_RX_DROP; } rd_set_count(rd, 0); @@ -772,7 +772,7 @@ static int vlsi_set_baud(vlsi_irda_dev_t *idev, unsigned iobase) int fifocnt; baudrate = idev->new_baud; - IRDA_DEBUG(2, "%s: %d -> %d\n", __FUNCTION__, idev->baud, idev->new_baud); + IRDA_DEBUG(2, "%s: %d -> %d\n", __func__, idev->baud, idev->new_baud); if (baudrate == 4000000) { mode = IFF_FIR; config = IRCFG_FIR; @@ -789,7 +789,7 @@ static int vlsi_set_baud(vlsi_irda_dev_t *idev, unsigned iobase) switch(baudrate) { default: IRDA_WARNING("%s: undefined baudrate %d - fallback to 9600!\n", - __FUNCTION__, baudrate); + __func__, baudrate); baudrate = 9600; /* fallthru */ case 2400: @@ -806,7 +806,7 @@ static int vlsi_set_baud(vlsi_irda_dev_t *idev, unsigned iobase) fifocnt = inw(iobase+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK; if (fifocnt != 0) { - IRDA_DEBUG(0, "%s: rx fifo not empty(%d)\n", __FUNCTION__, fifocnt); + IRDA_DEBUG(0, "%s: rx fifo not empty(%d)\n", __func__, fifocnt); } outw(0, iobase+VLSI_PIO_IRENABLE); @@ -830,14 +830,14 @@ static int vlsi_set_baud(vlsi_irda_dev_t *idev, unsigned iobase) config ^= IRENABLE_SIR_ON; if (config != (IRENABLE_PHYANDCLOCK|IRENABLE_ENRXST)) { - IRDA_WARNING("%s: failed to set %s mode!\n", __FUNCTION__, + IRDA_WARNING("%s: failed to set %s mode!\n", __func__, (mode==IFF_SIR)?"SIR":((mode==IFF_MIR)?"MIR":"FIR")); ret = -1; } else { if (inw(iobase+VLSI_PIO_PHYCTL) != nphyctl) { IRDA_WARNING("%s: failed to apply baudrate %d\n", - __FUNCTION__, baudrate); + __func__, baudrate); ret = -1; } else { @@ -849,7 +849,7 @@ static int vlsi_set_baud(vlsi_irda_dev_t *idev, unsigned iobase) } if (ret) - vlsi_reg_debug(iobase,__FUNCTION__); + vlsi_reg_debug(iobase,__func__); return ret; } @@ -982,7 +982,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (len >= r->len-5) IRDA_WARNING("%s: possible buffer overflow with SIR wrapping!\n", - __FUNCTION__); + __func__); } else { /* hw deals with MIR/FIR mode wrapping */ @@ -1027,7 +1027,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) fifocnt = inw(ndev->base_addr+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK; if (fifocnt != 0) { - IRDA_DEBUG(0, "%s: rx fifo not empty(%d)\n", __FUNCTION__, fifocnt); + IRDA_DEBUG(0, "%s: rx fifo not empty(%d)\n", __func__, fifocnt); } config = inw(iobase+VLSI_PIO_IRCFG); @@ -1040,7 +1040,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (ring_put(r) == NULL) { netif_stop_queue(ndev); - IRDA_DEBUG(3, "%s: tx ring full - queue stopped\n", __FUNCTION__); + IRDA_DEBUG(3, "%s: tx ring full - queue stopped\n", __func__); } spin_unlock_irqrestore(&idev->lock, flags); @@ -1049,7 +1049,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) drop_unlock: spin_unlock_irqrestore(&idev->lock, flags); drop: - IRDA_WARNING("%s: dropping packet - %s\n", __FUNCTION__, msg); + IRDA_WARNING("%s: dropping packet - %s\n", __func__, msg); dev_kfree_skb_any(skb); idev->stats.tx_errors++; idev->stats.tx_dropped++; @@ -1106,7 +1106,7 @@ static void vlsi_tx_interrupt(struct net_device *ndev) fifocnt = inw(iobase+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK; if (fifocnt != 0) { IRDA_DEBUG(0, "%s: rx fifo not empty(%d)\n", - __FUNCTION__, fifocnt); + __func__, fifocnt); } outw(config | IRCFG_ENTX, iobase+VLSI_PIO_IRCFG); } @@ -1115,7 +1115,7 @@ static void vlsi_tx_interrupt(struct net_device *ndev) if (netif_queue_stopped(ndev) && !idev->new_baud) { netif_wake_queue(ndev); - IRDA_DEBUG(3, "%s: queue awoken\n", __FUNCTION__); + IRDA_DEBUG(3, "%s: queue awoken\n", __func__); } } @@ -1138,7 +1138,7 @@ static void vlsi_unarm_tx(vlsi_irda_dev_t *idev) dev_kfree_skb_any(rd->skb); rd->skb = NULL; } - IRDA_DEBUG(0, "%s - dropping tx packet\n", __FUNCTION__); + IRDA_DEBUG(0, "%s - dropping tx packet\n", __func__); ret = -VLSI_TX_DROP; } else @@ -1188,7 +1188,7 @@ static int vlsi_start_clock(struct pci_dev *pdev) if (count < 3) { if (clksrc == 1) { /* explicitly asked for PLL hence bail out */ IRDA_ERROR("%s: no PLL or failed to lock!\n", - __FUNCTION__); + __func__); clkctl = CLKCTL_CLKSTP; pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl); return -1; @@ -1197,7 +1197,7 @@ static int vlsi_start_clock(struct pci_dev *pdev) clksrc = 3; /* fallback to 40MHz XCLK (OB800) */ IRDA_DEBUG(0, "%s: PLL not locked, fallback to clksrc=%d\n", - __FUNCTION__, clksrc); + __func__, clksrc); } else clksrc = 1; /* got successful PLL lock */ @@ -1269,7 +1269,7 @@ static int vlsi_init_chip(struct pci_dev *pdev) /* start the clock and clean the registers */ if (vlsi_start_clock(pdev)) { - IRDA_ERROR("%s: no valid clock source\n", __FUNCTION__); + IRDA_ERROR("%s: no valid clock source\n", __func__); return -1; } iobase = ndev->base_addr; @@ -1386,7 +1386,7 @@ static void vlsi_tx_timeout(struct net_device *ndev) vlsi_irda_dev_t *idev = ndev->priv; - vlsi_reg_debug(ndev->base_addr, __FUNCTION__); + vlsi_reg_debug(ndev->base_addr, __func__); vlsi_ring_debug(idev->tx_ring); if (netif_running(ndev)) @@ -1401,7 +1401,7 @@ static void vlsi_tx_timeout(struct net_device *ndev) if (vlsi_start_hw(idev)) IRDA_ERROR("%s: failed to restart hw - %s(%s) unusable!\n", - __FUNCTION__, pci_name(idev->pdev), ndev->name); + __func__, pci_name(idev->pdev), ndev->name); else netif_start_queue(ndev); } @@ -1446,7 +1446,7 @@ static int vlsi_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) break; default: IRDA_WARNING("%s: notsupp - cmd=%04x\n", - __FUNCTION__, cmd); + __func__, cmd); ret = -EOPNOTSUPP; } @@ -1491,7 +1491,7 @@ static irqreturn_t vlsi_interrupt(int irq, void *dev_instance) if (boguscount <= 0) IRDA_MESSAGE("%s: too much work in interrupt!\n", - __FUNCTION__); + __func__); return IRQ_RETVAL(handled); } @@ -1504,7 +1504,7 @@ static int vlsi_open(struct net_device *ndev) char hwname[32]; if (pci_request_regions(idev->pdev, drivername)) { - IRDA_WARNING("%s: io resource busy\n", __FUNCTION__); + IRDA_WARNING("%s: io resource busy\n", __func__); goto errout; } ndev->base_addr = pci_resource_start(idev->pdev,0); @@ -1519,7 +1519,7 @@ static int vlsi_open(struct net_device *ndev) if (request_irq(ndev->irq, vlsi_interrupt, IRQF_SHARED, drivername, ndev)) { IRDA_WARNING("%s: couldn't get IRQ: %d\n", - __FUNCTION__, ndev->irq); + __func__, ndev->irq); goto errout_io; } @@ -1540,7 +1540,7 @@ static int vlsi_open(struct net_device *ndev) netif_start_queue(ndev); - IRDA_MESSAGE("%s: device %s operational\n", __FUNCTION__, ndev->name); + IRDA_MESSAGE("%s: device %s operational\n", __func__, ndev->name); return 0; @@ -1574,7 +1574,7 @@ static int vlsi_close(struct net_device *ndev) pci_release_regions(idev->pdev); - IRDA_MESSAGE("%s: device %s stopped\n", __FUNCTION__, ndev->name); + IRDA_MESSAGE("%s: device %s stopped\n", __func__, ndev->name); return 0; } @@ -1593,7 +1593,7 @@ static int vlsi_irda_init(struct net_device *ndev) if (pci_set_dma_mask(pdev,DMA_MASK_USED_BY_HW) || pci_set_dma_mask(pdev,DMA_MASK_MSTRPAGE)) { - IRDA_ERROR("%s: aborting due to PCI BM-DMA address limitations\n", __FUNCTION__); + IRDA_ERROR("%s: aborting due to PCI BM-DMA address limitations\n", __func__); return -1; } @@ -1645,14 +1645,14 @@ vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id) if ( !pci_resource_start(pdev,0) || !(pci_resource_flags(pdev,0) & IORESOURCE_IO) ) { - IRDA_ERROR("%s: bar 0 invalid", __FUNCTION__); + IRDA_ERROR("%s: bar 0 invalid", __func__); goto out_disable; } ndev = alloc_irdadev(sizeof(*idev)); if (ndev==NULL) { IRDA_ERROR("%s: Unable to allocate device memory.\n", - __FUNCTION__); + __func__); goto out_disable; } @@ -1667,7 +1667,7 @@ vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_freedev; if (register_netdev(ndev) < 0) { - IRDA_ERROR("%s: register_netdev failed\n", __FUNCTION__); + IRDA_ERROR("%s: register_netdev failed\n", __func__); goto out_freedev; } @@ -1678,7 +1678,7 @@ vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id) vlsi_proc_root, VLSI_PROC_FOPS, ndev); if (!ent) { IRDA_WARNING("%s: failed to create proc entry\n", - __FUNCTION__); + __func__); } else { ent->size = 0; } @@ -1745,7 +1745,7 @@ static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state) if (!ndev) { IRDA_ERROR("%s - %s: no netdevice \n", - __FUNCTION__, pci_name(pdev)); + __func__, pci_name(pdev)); return 0; } idev = ndev->priv; @@ -1756,7 +1756,7 @@ static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state) pdev->current_state = state.event; } else - IRDA_ERROR("%s - %s: invalid suspend request %u -> %u\n", __FUNCTION__, pci_name(pdev), pdev->current_state, state.event); + IRDA_ERROR("%s - %s: invalid suspend request %u -> %u\n", __func__, pci_name(pdev), pdev->current_state, state.event); mutex_unlock(&idev->mtx); return 0; } @@ -1784,7 +1784,7 @@ static int vlsi_irda_resume(struct pci_dev *pdev) if (!ndev) { IRDA_ERROR("%s - %s: no netdevice \n", - __FUNCTION__, pci_name(pdev)); + __func__, pci_name(pdev)); return 0; } idev = ndev->priv; @@ -1792,7 +1792,7 @@ static int vlsi_irda_resume(struct pci_dev *pdev) if (pdev->current_state == 0) { mutex_unlock(&idev->mtx); IRDA_WARNING("%s - %s: already resumed\n", - __FUNCTION__, pci_name(pdev)); + __func__, pci_name(pdev)); return 0; } @@ -1811,7 +1811,7 @@ static int vlsi_irda_resume(struct pci_dev *pdev) * now we explicitly set pdev->current_state = 0 after enabling the * device and independently resume_ok should catch any garbage config. */ - IRDA_WARNING("%s - hm, nothing to resume?\n", __FUNCTION__); + IRDA_WARNING("%s - hm, nothing to resume?\n", __func__); mutex_unlock(&idev->mtx); return 0; } diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h index c8b9c74eea5..9b1884329fb 100644 --- a/drivers/net/irda/vlsi_ir.h +++ b/drivers/net/irda/vlsi_ir.h @@ -617,7 +617,7 @@ static inline void rd_set_addr_status(struct ring_descr *rd, dma_addr_t a, u8 s) */ if ((a & ~DMA_MASK_MSTRPAGE)>>24 != MSTRPAGE_VALUE) { - IRDA_ERROR("%s: pci busaddr inconsistency!\n", __FUNCTION__); + IRDA_ERROR("%s: pci busaddr inconsistency!\n", __func__); dump_stack(); return; } diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 9fd2451b0fb..002a6d769f2 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -114,7 +114,7 @@ static int __init w83977af_init(void) { int i; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); for (i=0; (io[i] < 2000) && (i < ARRAY_SIZE(dev_self)); i++) { if (w83977af_open(i, io[i], irq[i], dma[i]) == 0) @@ -133,7 +133,7 @@ static void __exit w83977af_cleanup(void) { int i; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); for (i=0; i < ARRAY_SIZE(dev_self); i++) { if (dev_self[i]) @@ -154,12 +154,12 @@ int w83977af_open(int i, unsigned int iobase, unsigned int irq, struct w83977af_ir *self; int err; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); /* Lock the port that we need */ if (!request_region(iobase, CHIP_IO_EXTENT, driver_name)) { IRDA_DEBUG(0, "%s(), can't get iobase of 0x%03x\n", - __FUNCTION__ , iobase); + __func__ , iobase); return -ENODEV; } @@ -241,7 +241,7 @@ int w83977af_open(int i, unsigned int iobase, unsigned int irq, err = register_netdev(dev); if (err) { - IRDA_ERROR("%s(), register_netdevice() failed!\n", __FUNCTION__); + IRDA_ERROR("%s(), register_netdevice() failed!\n", __func__); goto err_out3; } IRDA_MESSAGE("IrDA: Registered device %s\n", dev->name); @@ -273,7 +273,7 @@ static int w83977af_close(struct w83977af_ir *self) { int iobase; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); iobase = self->io.fir_base; @@ -294,7 +294,7 @@ static int w83977af_close(struct w83977af_ir *self) /* Release the PORT that this driver is using */ IRDA_DEBUG(0 , "%s(), Releasing Region %03x\n", - __FUNCTION__ , self->io.fir_base); + __func__ , self->io.fir_base); release_region(self->io.fir_base, self->io.fir_ext); if (self->tx_buff.head) @@ -316,7 +316,7 @@ int w83977af_probe( int iobase, int irq, int dma) int i; for (i=0; i < 2; i++) { - IRDA_DEBUG( 0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG( 0, "%s()\n", __func__ ); #ifdef CONFIG_USE_W977_PNP /* Enter PnP configuration mode */ w977_efm_enter(efbase[i]); @@ -403,7 +403,7 @@ int w83977af_probe( int iobase, int irq, int dma) return 0; } else { /* Try next extented function register address */ - IRDA_DEBUG( 0, "%s(), Wrong chip version", __FUNCTION__ ); + IRDA_DEBUG( 0, "%s(), Wrong chip version", __func__ ); } } return -1; @@ -439,19 +439,19 @@ void w83977af_change_speed(struct w83977af_ir *self, __u32 speed) case 115200: outb(0x01, iobase+ABLL); break; case 576000: ir_mode = HCR_MIR_576; - IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __func__ ); break; case 1152000: ir_mode = HCR_MIR_1152; - IRDA_DEBUG(0, "%s(), handling baud of 1152000\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), handling baud of 1152000\n", __func__ ); break; case 4000000: ir_mode = HCR_FIR; - IRDA_DEBUG(0, "%s(), handling baud of 4000000\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), handling baud of 4000000\n", __func__ ); break; default: ir_mode = HCR_FIR; - IRDA_DEBUG(0, "%s(), unknown baud rate of %d\n", __FUNCTION__ , speed); + IRDA_DEBUG(0, "%s(), unknown baud rate of %d\n", __func__ , speed); break; } @@ -501,7 +501,7 @@ int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) iobase = self->io.fir_base; - IRDA_DEBUG(4, "%s(%ld), skb->len=%d\n", __FUNCTION__ , jiffies, + IRDA_DEBUG(4, "%s(%ld), skb->len=%d\n", __func__ , jiffies, (int) skb->len); /* Lock transmit buffer */ @@ -549,7 +549,7 @@ int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) outb(ICR_ETMRI, iobase+ICR); } else { #endif - IRDA_DEBUG(4, "%s(%ld), mtt=%d\n", __FUNCTION__ , jiffies, mtt); + IRDA_DEBUG(4, "%s(%ld), mtt=%d\n", __func__ , jiffies, mtt); if (mtt) udelay(mtt); @@ -591,7 +591,7 @@ static void w83977af_dma_write(struct w83977af_ir *self, int iobase) unsigned long flags; __u8 hcr; #endif - IRDA_DEBUG(4, "%s(), len=%d\n", __FUNCTION__ , self->tx_buff.len); + IRDA_DEBUG(4, "%s(), len=%d\n", __func__ , self->tx_buff.len); /* Save current set */ set = inb(iobase+SSR); @@ -643,7 +643,7 @@ static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size) int actual = 0; __u8 set; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); /* Save current bank */ set = inb(iobase+SSR); @@ -651,11 +651,11 @@ static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size) switch_bank(iobase, SET0); if (!(inb_p(iobase+USR) & USR_TSRE)) { IRDA_DEBUG(4, - "%s(), warning, FIFO not empty yet!\n", __FUNCTION__ ); + "%s(), warning, FIFO not empty yet!\n", __func__ ); fifo_size -= 17; IRDA_DEBUG(4, "%s(), %d bytes left in tx fifo\n", - __FUNCTION__ , fifo_size); + __func__ , fifo_size); } /* Fill FIFO with current frame */ @@ -665,7 +665,7 @@ static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size) } IRDA_DEBUG(4, "%s(), fifo_size %d ; %d sent of %d\n", - __FUNCTION__ , fifo_size, actual, len); + __func__ , fifo_size, actual, len); /* Restore bank */ outb(set, iobase+SSR); @@ -685,7 +685,7 @@ static void w83977af_dma_xmit_complete(struct w83977af_ir *self) int iobase; __u8 set; - IRDA_DEBUG(4, "%s(%ld)\n", __FUNCTION__ , jiffies); + IRDA_DEBUG(4, "%s(%ld)\n", __func__ , jiffies); IRDA_ASSERT(self != NULL, return;); @@ -700,7 +700,7 @@ static void w83977af_dma_xmit_complete(struct w83977af_ir *self) /* Check for underrrun! */ if (inb(iobase+AUDR) & AUDR_UNDR) { - IRDA_DEBUG(0, "%s(), Transmit underrun!\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), Transmit underrun!\n", __func__ ); self->stats.tx_errors++; self->stats.tx_fifo_errors++; @@ -741,7 +741,7 @@ int w83977af_dma_receive(struct w83977af_ir *self) #endif IRDA_ASSERT(self != NULL, return -1;); - IRDA_DEBUG(4, "%s\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s\n", __func__ ); iobase= self->io.fir_base; @@ -812,7 +812,7 @@ int w83977af_dma_receive_complete(struct w83977af_ir *self) __u8 set; __u8 status; - IRDA_DEBUG(4, "%s\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s\n", __func__ ); st_fifo = &self->st_fifo; @@ -892,7 +892,7 @@ int w83977af_dma_receive_complete(struct w83977af_ir *self) skb = dev_alloc_skb(len+1); if (skb == NULL) { printk(KERN_INFO - "%s(), memory squeeze, dropping frame.\n", __FUNCTION__); + "%s(), memory squeeze, dropping frame.\n", __func__); /* Restore set register */ outb(set, iobase+SSR); @@ -943,7 +943,7 @@ static void w83977af_pio_receive(struct w83977af_ir *self) __u8 byte = 0x00; int iobase; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); @@ -970,7 +970,7 @@ static __u8 w83977af_sir_interrupt(struct w83977af_ir *self, int isr) __u8 set; int iobase; - IRDA_DEBUG(4, "%s(), isr=%#x\n", __FUNCTION__ , isr); + IRDA_DEBUG(4, "%s(), isr=%#x\n", __func__ , isr); iobase = self->io.fir_base; /* Transmit FIFO low on data */ @@ -1007,7 +1007,7 @@ static __u8 w83977af_sir_interrupt(struct w83977af_ir *self, int isr) /* Check if we need to change the speed? */ if (self->new_speed) { IRDA_DEBUG(2, - "%s(), Changing speed!\n", __FUNCTION__ ); + "%s(), Changing speed!\n", __func__ ); w83977af_change_speed(self, self->new_speed); self->new_speed = 0; } @@ -1189,7 +1189,7 @@ static int w83977af_net_open(struct net_device *dev) char hwname[32]; __u8 set; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); IRDA_ASSERT(dev != NULL, return -1;); self = (struct w83977af_ir *) dev->priv; @@ -1252,7 +1252,7 @@ static int w83977af_net_close(struct net_device *dev) int iobase; __u8 set; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); IRDA_ASSERT(dev != NULL, return -1;); @@ -1307,7 +1307,7 @@ static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) IRDA_ASSERT(self != NULL, return -1;); - IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__ , dev->name, cmd); + IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __func__ , dev->name, cmd); spin_lock_irqsave(&self->lock, flags); -- cgit v1.2.3 From e8389f0c44652ee63d95bc0a7f8d565ac25dac77 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 24 Jul 2008 16:38:06 +0100 Subject: pata_ali: misplaced pci_dev_put() The ali_init_one() function does a search for an isa_bridge, but then fails to release it if the revision information was not correctly found. the problem comes from: isa_bridge = pci_get_device(...); if (isa_bridge && ...) { pci_dev_put(isa_bridge); } where the pci_dev_put() is never called if isa_bridge was valid but the extra checks on the chip-revision fail to match. Signed-off-by: Ben Dooks Signed-off-by: Jeff Garzik --- drivers/ata/pata_ali.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 0f3e659db99..5ca70fa1f58 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -550,8 +550,9 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) pci_read_config_byte(isa_bridge, 0x5E, &tmp); if ((tmp & 0x1E) == 0x12) ppi[0] = &info_20_udma; - pci_dev_put(isa_bridge); } + pci_dev_put(isa_bridge); + return ata_pci_sff_init_one(pdev, ppi, &ali_sht, NULL); } -- cgit v1.2.3 From bfce5e0179ad059035df28558724ff60af708e09 Mon Sep 17 00:00:00 2001 From: "JosephChan@via.com.tw" Date: Wed, 30 Jul 2008 12:32:48 -0700 Subject: pata_via: add VX800 flag; add function for fixing h/w bugs Add flag VIA_SATA_PATA for vx800, VX800 uses the same chipset(0x0581/0x5324) as CX700, which has 1 PATA channel(Master/Slave) and 1 SATA channel(Master/Slave) Add function . This is to fix the internal bug of VIA chipsets, which will reset the device register after changing the IEN bit in CTL register Signed-off-by: Joseph Chan Cc: Tejun Heo Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/pata_via.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 708ed144ede..57d951b11f2 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -98,7 +98,8 @@ static const struct via_isa_bridge { u8 rev_max; u16 flags; } via_isa_bridges[] = { - { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, + { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, VIA_UDMA_133 | + VIA_BAD_AST | VIA_SATA_PATA }, { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA }, @@ -322,6 +323,65 @@ static void via_set_dmamode(struct ata_port *ap, struct ata_device *adev) via_do_set_mode(ap, adev, adev->dma_mode, tclock[mode], set_ast, udma[mode]); } +/** + * via_ata_sff_tf_load - send taskfile registers to host controller + * @ap: Port to which output is sent + * @tf: ATA taskfile register set + * + * Outputs ATA taskfile to standard ATA host controller. + * + * Note: This is to fix the internal bug of via chipsets, which + * will reset the device register after changing the IEN bit on + * ctl register + */ +static void via_ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + if (tf->ctl != ap->last_ctl) { + iowrite8(tf->ctl, ioaddr->ctl_addr); + iowrite8(tf->device, ioaddr->device_addr); + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + } + + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + iowrite8(tf->hob_feature, ioaddr->feature_addr); + iowrite8(tf->hob_nsect, ioaddr->nsect_addr); + iowrite8(tf->hob_lbal, ioaddr->lbal_addr); + iowrite8(tf->hob_lbam, ioaddr->lbam_addr); + iowrite8(tf->hob_lbah, ioaddr->lbah_addr); + VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n", + tf->hob_feature, + tf->hob_nsect, + tf->hob_lbal, + tf->hob_lbam, + tf->hob_lbah); + } + + if (is_addr) { + iowrite8(tf->feature, ioaddr->feature_addr); + iowrite8(tf->nsect, ioaddr->nsect_addr); + iowrite8(tf->lbal, ioaddr->lbal_addr); + iowrite8(tf->lbam, ioaddr->lbam_addr); + iowrite8(tf->lbah, ioaddr->lbah_addr); + VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", + tf->feature, + tf->nsect, + tf->lbal, + tf->lbam, + tf->lbah); + } + + if (tf->flags & ATA_TFLAG_DEVICE) { + iowrite8(tf->device, ioaddr->device_addr); + VPRINTK("device 0x%X\n", tf->device); + } + + ata_wait_idle(ap); +} + static struct scsi_host_template via_sht = { ATA_BMDMA_SHT(DRV_NAME), }; @@ -332,11 +392,13 @@ static struct ata_port_operations via_port_ops = { .set_piomode = via_set_piomode, .set_dmamode = via_set_dmamode, .prereset = via_pre_reset, + .sff_tf_load = via_ata_tf_load, }; static struct ata_port_operations via_port_ops_noirq = { .inherits = &via_port_ops, .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_tf_load = via_ata_tf_load, }; /** -- cgit v1.2.3 From 2486fa561a3192bbbec39c7feef87a1e07bd6342 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 31 Jul 2008 07:52:40 +0900 Subject: libata: update atapi disable handling Global and per-LLD ATAPI disable checks were done in the command issue path probably because it was left out during EH conversion. On affected machines, this can cause lots of warning messages. Move them to where they belong - the probing path. Reported by Chunbo Luo. Signed-off-by: Tejun Heo Cc: Chunbo Luo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 12 +++++++++++- drivers/ata/libata-scsi.c | 34 ++-------------------------------- drivers/ata/libata.h | 1 - 3 files changed, 13 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 9bef1a84fe3..9cd04f68410 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -120,7 +120,7 @@ static char ata_force_param_buf[PAGE_SIZE] __initdata; module_param_string(force, ata_force_param_buf, sizeof(ata_force_param_buf), 0); MODULE_PARM_DESC(force, "Force ATA configurations including cable type, link speed and transfer mode (see Documentation/kernel-parameters.txt for details)"); -int atapi_enabled = 1; +static int atapi_enabled = 1; module_param(atapi_enabled, int, 0444); MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)"); @@ -2142,6 +2142,16 @@ int ata_dev_configure(struct ata_device *dev) return 0; } + if ((!atapi_enabled || (ap->flags & ATA_FLAG_NO_ATAPI)) && + dev->class == ATA_DEV_ATAPI) { + ata_dev_printk(dev, KERN_WARNING, + "WARNING: ATAPI is %s, device ignored.\n", + atapi_enabled ? "not supported with this driver" + : "disabled"); + ata_dev_disable(dev); + return 0; + } + /* let ACPI work its magic */ rc = ata_acpi_on_devcfg(dev); if (rc) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index f3b4b15a8dc..b9d3ba423cb 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2550,36 +2550,6 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap, return ata_find_dev(ap, devno); } -/** - * ata_scsi_dev_enabled - determine if device is enabled - * @dev: ATA device - * - * Determine if commands should be sent to the specified device. - * - * LOCKING: - * spin_lock_irqsave(host lock) - * - * RETURNS: - * 0 if commands are not allowed / 1 if commands are allowed - */ - -static int ata_scsi_dev_enabled(struct ata_device *dev) -{ - if (unlikely(!ata_dev_enabled(dev))) - return 0; - - if (!atapi_enabled || (dev->link->ap->flags & ATA_FLAG_NO_ATAPI)) { - if (unlikely(dev->class == ATA_DEV_ATAPI)) { - ata_dev_printk(dev, KERN_WARNING, - "WARNING: ATAPI is %s, device ignored.\n", - atapi_enabled ? "not supported with this driver" : "disabled"); - return 0; - } - } - - return 1; -} - /** * ata_scsi_find_dev - lookup ata_device from scsi_cmnd * @ap: ATA port to which the device is attached @@ -2601,7 +2571,7 @@ ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev) { struct ata_device *dev = __ata_scsi_find_dev(ap, scsidev); - if (unlikely(!dev || !ata_scsi_dev_enabled(dev))) + if (unlikely(!dev || !ata_dev_enabled(dev))) return NULL; return dev; @@ -3622,7 +3592,7 @@ int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), ata_scsi_dump_cdb(ap, cmd); - if (likely(ata_scsi_dev_enabled(ap->link.device))) + if (likely(ata_dev_enabled(ap->link.device))) rc = __ata_scsi_queuecmd(cmd, done, ap->link.device); else { cmd->result = (DID_BAD_TARGET << 16); diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index f6f9c28ec7f..ade5c75b614 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -66,7 +66,6 @@ enum { extern unsigned int ata_print_id; extern struct workqueue_struct *ata_aux_wq; -extern int atapi_enabled; extern int atapi_passthru16; extern int libata_fua; extern int libata_noacpi; -- cgit v1.2.3 From 49ea3b04971ece6a5efe5d7b763ad9d2f169d441 Mon Sep 17 00:00:00 2001 From: Elias Oltmanns Date: Wed, 30 Jul 2008 12:32:39 -0700 Subject: libata-core: make sure that ata_force_tbl is freed in case of an error Fix a potential memory leak when ata_init() encounters an error. Signed-off-by: Elias Oltmanns Cc: Tejun Heo Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 9cd04f68410..f69d1548b56 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6098,16 +6098,20 @@ static int __init ata_init(void) ata_wq = create_workqueue("ata"); if (!ata_wq) - return -ENOMEM; + goto free_force_tbl; ata_aux_wq = create_singlethread_workqueue("ata_aux"); - if (!ata_aux_wq) { - destroy_workqueue(ata_wq); - return -ENOMEM; - } + if (!ata_aux_wq) + goto free_wq; printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n"); return 0; + +free_wq: + destroy_workqueue(ata_wq); +free_force_tbl: + kfree(ata_force_tbl); + return -ENOMEM; } static void __exit ata_exit(void) -- cgit v1.2.3 From 487eff68e42287fd45cf178063f1ce1bad23c612 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 29 Jul 2008 15:06:26 +0900 Subject: ata_piix: subsys 106b:00a3 is apple ich8m too Subsys 106b:00a3 also is the weird apple ich8m which chokes when the latter two ports are accessed, add it. Reported by Felipe Sere. Signed-off-by: Tejun Heo Cc: Felipe Sere Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index a90ae03f56b..c294121fd69 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -250,6 +250,7 @@ static const struct pci_device_id piix_pci_tbl[] = { /* Mobile SATA Controller IDE (ICH8M), Apple */ { 0x8086, 0x2828, 0x106b, 0x00a0, 0, 0, ich8m_apple_sata }, { 0x8086, 0x2828, 0x106b, 0x00a1, 0, 0, ich8m_apple_sata }, + { 0x8086, 0x2828, 0x106b, 0x00a3, 0, 0, ich8m_apple_sata }, /* Mobile SATA Controller IDE (ICH8M) */ { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, /* SATA Controller IDE (ICH9) */ -- cgit v1.2.3 From 963e4975c6f93c148ca809d986d412201df9af89 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 24 Jul 2008 17:16:06 +0100 Subject: pata_it821x: Driver updates and reworking - Add support for the RDC 1010 variant - Rework the core library to have a read_id method. This allows the hacky bits of it821x to go and prepares us for pata_hd - Switch from WARN to BUG in ata_id_string as it will reboot if you get it wrong so WARN won't be seen - Allow the issue of command 0xFC on the 821x. This is needed to query rebuild status. - Tidy up printk formatting - Do more ident rewriting on RAID volumes to handle firmware provided ident data which is rather wonky - Report the firmware revision and device layout in RAID mode - Don't try and disable raid on the 8211 or RDC - they don't have the relevant bits Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 31 +++++- drivers/ata/pata_it821x.c | 270 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 262 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f69d1548b56..5ba96c5052c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1132,6 +1132,8 @@ void ata_id_string(const u16 *id, unsigned char *s, { unsigned int c; + BUG_ON(len & 1); + while (len > 0) { c = id[ofs] >> 8; *s = c; @@ -1165,8 +1167,6 @@ void ata_id_c_string(const u16 *id, unsigned char *s, { unsigned char *p; - WARN_ON(!(len & 1)); - ata_id_string(id, s, ofs, len - 1); p = s + strnlen(s, len - 1); @@ -1885,6 +1885,23 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev) return 3 << ATA_SHIFT_PIO; } +/** + * ata_do_dev_read_id - default ID read method + * @dev: device + * @tf: proposed taskfile + * @id: data buffer + * + * Issue the identify taskfile and hand back the buffer containing + * identify data. For some RAID controllers and for pre ATA devices + * this function is wrapped or replaced by the driver + */ +unsigned int ata_do_dev_read_id(struct ata_device *dev, + struct ata_taskfile *tf, u16 *id) +{ + return ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE, + id, sizeof(id[0]) * ATA_ID_WORDS, 0); +} + /** * ata_dev_read_id - Read ID data from the specified device * @dev: target device @@ -1920,7 +1937,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, if (ata_msg_ctl(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __func__); - retry: +retry: ata_tf_init(dev, &tf); switch (class) { @@ -1948,8 +1965,11 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, */ tf.flags |= ATA_TFLAG_POLLING; - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, - id, sizeof(id[0]) * ATA_ID_WORDS, 0); + if (ap->ops->read_id) + err_mask = ap->ops->read_id(dev, &tf, id); + else + err_mask = ata_do_dev_read_id(dev, &tf, id); + if (err_mask) { if (err_mask & AC_ERR_NODEV_HINT) { ata_dev_printk(dev, KERN_DEBUG, @@ -6283,6 +6303,7 @@ EXPORT_SYMBOL_GPL(ata_host_resume); #endif /* CONFIG_PM */ EXPORT_SYMBOL_GPL(ata_id_string); EXPORT_SYMBOL_GPL(ata_id_c_string); +EXPORT_SYMBOL_GPL(ata_do_dev_read_id); EXPORT_SYMBOL_GPL(ata_scsi_simulate); EXPORT_SYMBOL_GPL(ata_pio_need_iordy); diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index e10816931b2..27843c70eb9 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -80,7 +80,7 @@ #define DRV_NAME "pata_it821x" -#define DRV_VERSION "0.3.8" +#define DRV_VERSION "0.4.0" struct it821x_dev { @@ -425,6 +425,8 @@ static unsigned int it821x_smart_qc_issue(struct ata_queued_cmd *qc) case ATA_CMD_WRITE_MULTI: case ATA_CMD_WRITE_MULTI_EXT: case ATA_CMD_ID_ATA: + case ATA_CMD_INIT_DEV_PARAMS: + case 0xFC: /* Internal 'report rebuild state' */ /* Arguably should just no-op this one */ case ATA_CMD_SET_FEATURES: return ata_sff_qc_issue(qc); @@ -509,7 +511,7 @@ static void it821x_dev_config(struct ata_device *adev) if (strstr(model_num, "Integrated Technology Express")) { /* RAID mode */ - printk(KERN_INFO "IT821x %sRAID%d volume", + ata_dev_printk(adev, KERN_INFO, "%sRAID%d volume", adev->id[147]?"Bootable ":"", adev->id[129]); if (adev->id[129] != 1) @@ -519,37 +521,51 @@ static void it821x_dev_config(struct ata_device *adev) /* This is a controller firmware triggered funny, don't report the drive faulty! */ adev->horkage &= ~ATA_HORKAGE_DIAGNOSTIC; + /* No HPA in 'smart' mode */ + adev->horkage |= ATA_HORKAGE_BROKEN_HPA; } /** - * it821x_ident_hack - Hack identify data up - * @ap: Port + * it821x_read_id - Hack identify data up + * @adev: device to read + * @tf: proposed taskfile + * @id: buffer for returned ident data * - * Walk the devices on this firmware driven port and slightly + * Query the devices on this firmware driven port and slightly * mash the identify data to stop us and common tools trying to * use features not firmware supported. The firmware itself does * some masking (eg SMART) but not enough. - * - * This is a bit of an abuse of the cable method, but it is the - * only method called at the right time. We could modify the libata - * core specifically for ident hacking but while we have one offender - * it seems better to keep the fallout localised. */ -static int it821x_ident_hack(struct ata_port *ap) +static unsigned int it821x_read_id(struct ata_device *adev, + struct ata_taskfile *tf, u16 *id) { - struct ata_device *adev; - ata_link_for_each_dev(adev, &ap->link) { - if (ata_dev_enabled(adev)) { - adev->id[84] &= ~(1 << 6); /* No FUA */ - adev->id[85] &= ~(1 << 10); /* No HPA */ - adev->id[76] = 0; /* No NCQ/AN etc */ - } + unsigned int err_mask; + unsigned char model_num[ATA_ID_PROD_LEN + 1]; + + err_mask = ata_do_dev_read_id(adev, tf, id); + if (err_mask) + return err_mask; + ata_id_c_string(id, model_num, ATA_ID_PROD, sizeof(model_num)); + + id[83] &= ~(1 << 12); /* Cache flush is firmware handled */ + id[83] &= ~(1 << 13); /* Ditto for LBA48 flushes */ + id[84] &= ~(1 << 6); /* No FUA */ + id[85] &= ~(1 << 10); /* No HPA */ + id[76] = 0; /* No NCQ/AN etc */ + + if (strstr(model_num, "Integrated Technology Express")) { + /* Set feature bits the firmware neglects */ + id[49] |= 0x0300; /* LBA, DMA */ + id[82] |= 0x0400; /* LBA48 */ + id[83] &= 0x7FFF; + id[83] |= 0x4000; /* Word 83 is valid */ + id[86] |= 0x0400; /* LBA48 on */ + id[ATA_ID_MAJOR_VER] |= 0x1F; } - return ata_cable_unknown(ap); + return err_mask; } - /** * it821x_check_atapi_dma - ATAPI DMA handler * @qc: Command we are about to issue @@ -577,6 +593,136 @@ static int it821x_check_atapi_dma(struct ata_queued_cmd *qc) return 0; } +/** + * it821x_display_disk - display disk setup + * @n: Device number + * @buf: Buffer block from firmware + * + * Produce a nice informative display of the device setup as provided + * by the firmware. + */ + +static void it821x_display_disk(int n, u8 *buf) +{ + unsigned char id[41]; + int mode = 0; + char *mtype; + char mbuf[8]; + char *cbl = "(40 wire cable)"; + + static const char *types[5] = { + "RAID0", "RAID1" "RAID 0+1", "JBOD", "DISK" + }; + + if (buf[52] > 4) /* No Disk */ + return; + + ata_id_c_string((u16 *)buf, id, 0, 41); + + if (buf[51]) { + mode = ffs(buf[51]); + mtype = "UDMA"; + } else if (buf[49]) { + mode = ffs(buf[49]); + mtype = "MWDMA"; + } + + if (buf[76]) + cbl = ""; + + if (mode) + snprintf(mbuf, 8, "%5s%d", mtype, mode - 1); + else + strcpy(mbuf, "PIO"); + if (buf[52] == 4) + printk(KERN_INFO "%d: %-6s %-8s %s %s\n", + n, mbuf, types[buf[52]], id, cbl); + else + printk(KERN_INFO "%d: %-6s %-8s Volume: %1d %s %s\n", + n, mbuf, types[buf[52]], buf[53], id, cbl); + if (buf[125] < 100) + printk(KERN_INFO "%d: Rebuilding: %d%%\n", n, buf[125]); +} + +/** + * it821x_firmware_command - issue firmware command + * @ap: IT821x port to interrogate + * @cmd: command + * @len: length + * + * Issue firmware commands expecting data back from the controller. We + * use this to issue commands that do not go via the normal paths. Other + * commands such as 0xFC can be issued normally. + */ + +static u8 *it821x_firmware_command(struct ata_port *ap, u8 cmd, int len) +{ + u8 status; + int n = 0; + u16 *buf = kmalloc(len, GFP_KERNEL); + if (buf == NULL) { + printk(KERN_ERR "it821x_firmware_command: Out of memory\n"); + return NULL; + } + /* This isn't quite a normal ATA command as we are talking to the + firmware not the drives */ + ap->ctl |= ATA_NIEN; + iowrite8(ap->ctl, ap->ioaddr.ctl_addr); + ata_wait_idle(ap); + iowrite8(ATA_DEVICE_OBS, ap->ioaddr.device_addr); + iowrite8(cmd, ap->ioaddr.command_addr); + udelay(1); + /* This should be almost immediate but a little paranoia goes a long + way. */ + while(n++ < 10) { + status = ioread8(ap->ioaddr.status_addr); + if (status & ATA_ERR) { + kfree(buf); + printk(KERN_ERR "it821x_firmware_command: rejected\n"); + return NULL; + } + if (status & ATA_DRQ) { + ioread16_rep(ap->ioaddr.data_addr, buf, len/2); + return (u8 *)buf; + } + mdelay(1); + } + kfree(buf); + printk(KERN_ERR "it821x_firmware_command: timeout\n"); + return NULL; +} + +/** + * it821x_probe_firmware - firmware reporting/setup + * @ap: IT821x port being probed + * + * Probe the firmware of the controller by issuing firmware command + * 0xFA and analysing the returned data. + */ + +static void it821x_probe_firmware(struct ata_port *ap) +{ + u8 *buf; + int i; + + /* This is a bit ugly as we can't just issue a task file to a device + as this is controller magic */ + + buf = it821x_firmware_command(ap, 0xFA, 512); + + if (buf != NULL) { + printk(KERN_INFO "pata_it821x: Firmware %02X/%02X/%02X%02X\n", + buf[505], + buf[506], + buf[507], + buf[508]); + for (i = 0; i < 4; i++) + it821x_display_disk(i, buf + 128 * i); + kfree(buf); + } +} + + /** * it821x_port_start - port setup @@ -610,6 +756,8 @@ static int it821x_port_start(struct ata_port *ap) /* Long I/O's although allowed in LBA48 space cause the onboard firmware to enter the twighlight zone */ /* No ATAPI DMA in this mode either */ + if (ap->port_no == 0) + it821x_probe_firmware(ap); } /* Pull the current clocks from 0x50 */ if (conf & (1 << (1 + ap->port_no))) @@ -631,6 +779,25 @@ static int it821x_port_start(struct ata_port *ap) return 0; } +/** + * it821x_rdc_cable - Cable detect for RDC1010 + * @ap: port we are checking + * + * Return the RDC1010 cable type. Unlike the IT821x we know how to do + * this and can do host side cable detect + */ + +static int it821x_rdc_cable(struct ata_port *ap) +{ + u16 r40; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + + pci_read_config_word(pdev, 0x40, &r40); + if (r40 & (1 << (2 + ap->port_no))) + return ATA_CBL_PATA40; + return ATA_CBL_PATA80; +} + static struct scsi_host_template it821x_sht = { ATA_BMDMA_SHT(DRV_NAME), }; @@ -641,9 +808,10 @@ static struct ata_port_operations it821x_smart_port_ops = { .check_atapi_dma= it821x_check_atapi_dma, .qc_issue = it821x_smart_qc_issue, - .cable_detect = it821x_ident_hack, + .cable_detect = ata_cable_80wire, .set_mode = it821x_smart_set_mode, .dev_config = it821x_dev_config, + .read_id = it821x_read_id, .port_start = it821x_port_start, }; @@ -664,8 +832,29 @@ static struct ata_port_operations it821x_passthru_port_ops = { .port_start = it821x_port_start, }; +static struct ata_port_operations it821x_rdc_port_ops = { + .inherits = &ata_bmdma_port_ops, + + .check_atapi_dma= it821x_check_atapi_dma, + .sff_dev_select = it821x_passthru_dev_select, + .bmdma_start = it821x_passthru_bmdma_start, + .bmdma_stop = it821x_passthru_bmdma_stop, + .qc_issue = it821x_passthru_qc_issue, + + .cable_detect = it821x_rdc_cable, + .set_piomode = it821x_passthru_set_piomode, + .set_dmamode = it821x_passthru_set_dmamode, + + .port_start = it821x_port_start, +}; + static void it821x_disable_raid(struct pci_dev *pdev) { + /* Neither the RDC nor the IT8211 */ + if (pdev->vendor != PCI_VENDOR_ID_ITE || + pdev->device != PCI_DEVICE_ID_ITE_8212) + return; + /* Reset local CPU, and set BIOS not ready */ pci_write_config_byte(pdev, 0x5E, 0x01); @@ -690,6 +879,7 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, + .udma_mask = ATA_UDMA6, .port_ops = &it821x_smart_port_ops }; static const struct ata_port_info info_passthru = { @@ -699,6 +889,13 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .udma_mask = ATA_UDMA6, .port_ops = &it821x_passthru_port_ops }; + static const struct ata_port_info info_rdc = { + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + /* No UDMA */ + .port_ops = &it821x_rdc_port_ops + }; const struct ata_port_info *ppi[] = { NULL, NULL }; static char *mode[2] = { "pass through", "smart" }; @@ -707,21 +904,25 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) rc = pcim_enable_device(pdev); if (rc) return rc; + + if (pdev->vendor == PCI_VENDOR_ID_RDC) { + ppi[0] = &info_rdc; + } else { + /* Force the card into bypass mode if so requested */ + if (it8212_noraid) { + printk(KERN_INFO DRV_NAME ": forcing bypass mode.\n"); + it821x_disable_raid(pdev); + } + pci_read_config_byte(pdev, 0x50, &conf); + conf &= 1; - /* Force the card into bypass mode if so requested */ - if (it8212_noraid) { - printk(KERN_INFO DRV_NAME ": forcing bypass mode.\n"); - it821x_disable_raid(pdev); + printk(KERN_INFO DRV_NAME": controller in %s mode.\n", + mode[conf]); + if (conf == 0) + ppi[0] = &info_passthru; + else + ppi[0] = &info_smart; } - pci_read_config_byte(pdev, 0x50, &conf); - conf &= 1; - - printk(KERN_INFO DRV_NAME ": controller in %s mode.\n", mode[conf]); - if (conf == 0) - ppi[0] = &info_passthru; - else - ppi[0] = &info_smart; - return ata_pci_sff_init_one(pdev, ppi, &it821x_sht, NULL); } @@ -745,6 +946,7 @@ static int it821x_reinit_one(struct pci_dev *pdev) static const struct pci_device_id it821x[] = { { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), }, { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), }, + { PCI_VDEVICE(RDC, 0x1010), }, { }, }; -- cgit v1.2.3 From 4a22442faeb33bdf34016a7b1f6b3d6ecd4e33e5 Mon Sep 17 00:00:00 2001 From: Jerry Hicks Date: Wed, 30 Jul 2008 12:49:59 -0700 Subject: [MTD] [NOR] drivers/mtd/chips/jedec_probe.c: fix Am29DL800BB device ID The device id for Am29DL800BB in jedec_probe.c is wrong. Reference: http://www.spansion.com/datasheets/21519c4.pdf I discovered this while working with u-boot. The u-boot folks mentioned Linux as an upstream reference, thought I'd post a heads-up here too. Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/chips/jedec_probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index dbba5abf0db..f84ab618214 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -41,7 +41,7 @@ /* AMD */ -#define AM29DL800BB 0x22C8 +#define AM29DL800BB 0x22CB #define AM29DL800BT 0x224A #define AM29F800BB 0x2258 -- cgit v1.2.3 From 6f5fd8e9b98423add5f67b964e7cc8733dd73460 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 31 Jul 2008 03:46:30 -0400 Subject: drivers/media, include/media: delete zero-length files Signed-off-by: Jeff Garzik --- drivers/media/video/planb.c | 0 drivers/media/video/planb.h | 0 drivers/media/video/saa7196.h | 0 drivers/media/video/videodev.c | 0 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 drivers/media/video/planb.c delete mode 100644 drivers/media/video/planb.h delete mode 100644 drivers/media/video/saa7196.h delete mode 100644 drivers/media/video/videodev.c (limited to 'drivers') diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/drivers/media/video/planb.h b/drivers/media/video/planb.h deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/drivers/media/video/saa7196.h b/drivers/media/video/saa7196.h deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c deleted file mode 100644 index e69de29bb2d..00000000000 -- cgit v1.2.3 From c3f26a269c2421f97f10cf8ed05d5099b573af4d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 31 Jul 2008 16:58:50 -0700 Subject: netdev: Fix lockdep warnings in multiqueue configurations. When support for multiple TX queues were added, the netif_tx_lock() routines we converted to iterate over all TX queues and grab each queue's spinlock. This causes heartburn for lockdep and it's not a healthy thing to do with lots of TX queues anyways. So modify this to use a top-level lock and a "frozen" state for the individual TX queues. Signed-off-by: David S. Miller --- drivers/net/ifb.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 0960e69b2da..e4fbefc8c82 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -69,18 +69,20 @@ static void ri_tasklet(unsigned long dev) struct net_device *_dev = (struct net_device *)dev; struct ifb_private *dp = netdev_priv(_dev); struct net_device_stats *stats = &_dev->stats; + struct netdev_queue *txq; struct sk_buff *skb; + txq = netdev_get_tx_queue(_dev, 0); dp->st_task_enter++; if ((skb = skb_peek(&dp->tq)) == NULL) { dp->st_txq_refl_try++; - if (netif_tx_trylock(_dev)) { + if (__netif_tx_trylock(txq)) { dp->st_rxq_enter++; while ((skb = skb_dequeue(&dp->rq)) != NULL) { skb_queue_tail(&dp->tq, skb); dp->st_rx2tx_tran++; } - netif_tx_unlock(_dev); + __netif_tx_unlock(txq); } else { /* reschedule */ dp->st_rxq_notenter++; @@ -115,7 +117,7 @@ static void ri_tasklet(unsigned long dev) BUG(); } - if (netif_tx_trylock(_dev)) { + if (__netif_tx_trylock(txq)) { dp->st_rxq_check++; if ((skb = skb_peek(&dp->rq)) == NULL) { dp->tasklet_pending = 0; @@ -123,10 +125,10 @@ static void ri_tasklet(unsigned long dev) netif_wake_queue(_dev); } else { dp->st_rxq_rsch++; - netif_tx_unlock(_dev); + __netif_tx_unlock(txq); goto resched; } - netif_tx_unlock(_dev); + __netif_tx_unlock(txq); } else { resched: dp->tasklet_pending = 1; -- cgit v1.2.3 From 388667bed591b2359713bb17d5de0cf56e961447 Mon Sep 17 00:00:00 2001 From: Arthur Jones Date: Fri, 25 Jul 2008 12:03:38 -0700 Subject: md: raid10: wake up frozen array When rescheduling a bio in raid10, we wake up the md thread, but if the array is frozen, this will have no effect. This causes the array to remain frozen for eternity. We add a wake_up to allow the array to de-freeze. This code is nearly identical to the raid1 code, which has this fix already. Signed-off-by: Arthur Jones Signed-off-by: NeilBrown --- drivers/md/raid10.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 2acea402524..8674a5f7e70 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -215,6 +215,9 @@ static void reschedule_retry(r10bio_t *r10_bio) conf->nr_queued ++; spin_unlock_irqrestore(&conf->device_lock, flags); + /* wake up frozen array... */ + wake_up(&conf->wait_barrier); + md_wakeup_thread(mddev->thread); } -- cgit v1.2.3 From 9b257714a3f6f5c3ea133c44d3442e2340734b65 Mon Sep 17 00:00:00 2001 From: Juerg Haefliger Date: Tue, 25 Mar 2008 21:49:02 -0700 Subject: hwmon: (dme1737) demacrofy for readability This patch gets rid of a couple of macros previously used for sysfs attribute generation and manipulation. This makes the source a little bigger but a lot more readable and maintainable. It also fixes an issue with pwm5 & pwm6 attributes not being created read-only initially. Signed-Off-By: Juerg Haefliger Acked-by: Jean Delvare Signed-off-by: Mark M. Hoffman --- drivers/hwmon/dme1737.c | 255 +++++++++++++++++++++++++++++------------------- 1 file changed, 154 insertions(+), 101 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index 7673f65877e..c24b5b370da 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -1501,9 +1501,9 @@ SENSOR_DEVICE_ATTR_PWM_1TO3(3); /* PWMs 5-6 */ #define SENSOR_DEVICE_ATTR_PWM_5TO6(ix) \ -static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO | S_IWUSR, \ +static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO, \ show_pwm, set_pwm, SYS_PWM, ix-1); \ -static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO | S_IWUSR, \ +static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO, \ show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \ show_pwm, NULL, SYS_PWM_ENABLE, ix-1) @@ -1517,91 +1517,75 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); /* for ISA devices */ -#define SENSOR_DEV_ATTR_IN(ix) \ -&sensor_dev_attr_in##ix##_input.dev_attr.attr, \ -&sensor_dev_attr_in##ix##_min.dev_attr.attr, \ -&sensor_dev_attr_in##ix##_max.dev_attr.attr, \ -&sensor_dev_attr_in##ix##_alarm.dev_attr.attr - -/* These attributes are read-writeable only if the chip is *not* locked */ -#define SENSOR_DEV_ATTR_TEMP_LOCK(ix) \ -&sensor_dev_attr_temp##ix##_offset.dev_attr.attr - -#define SENSOR_DEV_ATTR_TEMP(ix) \ -SENSOR_DEV_ATTR_TEMP_LOCK(ix), \ -&sensor_dev_attr_temp##ix##_input.dev_attr.attr, \ -&sensor_dev_attr_temp##ix##_min.dev_attr.attr, \ -&sensor_dev_attr_temp##ix##_max.dev_attr.attr, \ -&sensor_dev_attr_temp##ix##_alarm.dev_attr.attr, \ -&sensor_dev_attr_temp##ix##_fault.dev_attr.attr - -/* These attributes are read-writeable only if the chip is *not* locked */ -#define SENSOR_DEV_ATTR_ZONE_LOCK(ix) \ -&sensor_dev_attr_zone##ix##_auto_point1_temp_hyst.dev_attr.attr, \ -&sensor_dev_attr_zone##ix##_auto_point1_temp.dev_attr.attr, \ -&sensor_dev_attr_zone##ix##_auto_point2_temp.dev_attr.attr, \ -&sensor_dev_attr_zone##ix##_auto_point3_temp.dev_attr.attr - -#define SENSOR_DEV_ATTR_ZONE(ix) \ -SENSOR_DEV_ATTR_ZONE_LOCK(ix), \ -&sensor_dev_attr_zone##ix##_auto_channels_temp.dev_attr.attr - -#define SENSOR_DEV_ATTR_FAN_1TO4(ix) \ -&sensor_dev_attr_fan##ix##_input.dev_attr.attr, \ -&sensor_dev_attr_fan##ix##_min.dev_attr.attr, \ -&sensor_dev_attr_fan##ix##_alarm.dev_attr.attr, \ -&sensor_dev_attr_fan##ix##_type.dev_attr.attr - -#define SENSOR_DEV_ATTR_FAN_5TO6(ix) \ -&sensor_dev_attr_fan##ix##_input.dev_attr.attr, \ -&sensor_dev_attr_fan##ix##_min.dev_attr.attr, \ -&sensor_dev_attr_fan##ix##_alarm.dev_attr.attr, \ -&sensor_dev_attr_fan##ix##_max.dev_attr.attr - -/* These attributes are read-writeable only if the chip is *not* locked */ -#define SENSOR_DEV_ATTR_PWM_1TO3_LOCK(ix) \ -&sensor_dev_attr_pwm##ix##_freq.dev_attr.attr, \ -&sensor_dev_attr_pwm##ix##_enable.dev_attr.attr, \ -&sensor_dev_attr_pwm##ix##_ramp_rate.dev_attr.attr, \ -&sensor_dev_attr_pwm##ix##_auto_channels_zone.dev_attr.attr, \ -&sensor_dev_attr_pwm##ix##_auto_pwm_min.dev_attr.attr, \ -&sensor_dev_attr_pwm##ix##_auto_point1_pwm.dev_attr.attr - -#define SENSOR_DEV_ATTR_PWM_1TO3(ix) \ -SENSOR_DEV_ATTR_PWM_1TO3_LOCK(ix), \ -&sensor_dev_attr_pwm##ix.dev_attr.attr, \ -&sensor_dev_attr_pwm##ix##_auto_point2_pwm.dev_attr.attr - -/* These attributes are read-writeable only if the chip is *not* locked */ -#define SENSOR_DEV_ATTR_PWM_5TO6_LOCK(ix) \ -&sensor_dev_attr_pwm##ix.dev_attr.attr, \ -&sensor_dev_attr_pwm##ix##_freq.dev_attr.attr - -#define SENSOR_DEV_ATTR_PWM_5TO6(ix) \ -SENSOR_DEV_ATTR_PWM_5TO6_LOCK(ix), \ -&sensor_dev_attr_pwm##ix##_enable.dev_attr.attr - /* This struct holds all the attributes that are always present and need to be * created unconditionally. The attributes that need modification of their * permissions are created read-only and write permissions are added or removed * on the fly when required */ static struct attribute *dme1737_attr[] ={ /* Voltages */ - SENSOR_DEV_ATTR_IN(0), - SENSOR_DEV_ATTR_IN(1), - SENSOR_DEV_ATTR_IN(2), - SENSOR_DEV_ATTR_IN(3), - SENSOR_DEV_ATTR_IN(4), - SENSOR_DEV_ATTR_IN(5), - SENSOR_DEV_ATTR_IN(6), + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in6_max.dev_attr.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, /* Temperatures */ - SENSOR_DEV_ATTR_TEMP(1), - SENSOR_DEV_ATTR_TEMP(2), - SENSOR_DEV_ATTR_TEMP(3), + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_fault.dev_attr.attr, + &sensor_dev_attr_temp1_offset.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, + &sensor_dev_attr_temp2_offset.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, + &sensor_dev_attr_temp3_offset.dev_attr.attr, /* Zones */ - SENSOR_DEV_ATTR_ZONE(1), - SENSOR_DEV_ATTR_ZONE(2), - SENSOR_DEV_ATTR_ZONE(3), + &sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr, + &sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_zone1_auto_channels_temp.dev_attr.attr, + &sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr, + &sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_zone2_auto_channels_temp.dev_attr.attr, + &sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr, + &sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr, /* Misc */ &dev_attr_vrm.attr, &dev_attr_cpu0_vid.attr, @@ -1616,23 +1600,48 @@ static const struct attribute_group dme1737_group = { * Their creation depends on the chip configuration which is determined during * module load. */ static struct attribute *dme1737_attr_pwm1[] = { - SENSOR_DEV_ATTR_PWM_1TO3(1), + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm1_freq.dev_attr.attr, + &sensor_dev_attr_pwm1_enable.dev_attr.attr, + &sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, NULL }; static struct attribute *dme1737_attr_pwm2[] = { - SENSOR_DEV_ATTR_PWM_1TO3(2), + &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm2_freq.dev_attr.attr, + &sensor_dev_attr_pwm2_enable.dev_attr.attr, + &sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, NULL }; static struct attribute *dme1737_attr_pwm3[] = { - SENSOR_DEV_ATTR_PWM_1TO3(3), + &sensor_dev_attr_pwm3.dev_attr.attr, + &sensor_dev_attr_pwm3_freq.dev_attr.attr, + &sensor_dev_attr_pwm3_enable.dev_attr.attr, + &sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, NULL }; static struct attribute *dme1737_attr_pwm5[] = { - SENSOR_DEV_ATTR_PWM_5TO6(5), + &sensor_dev_attr_pwm5.dev_attr.attr, + &sensor_dev_attr_pwm5_freq.dev_attr.attr, + &sensor_dev_attr_pwm5_enable.dev_attr.attr, NULL }; static struct attribute *dme1737_attr_pwm6[] = { - SENSOR_DEV_ATTR_PWM_5TO6(6), + &sensor_dev_attr_pwm6.dev_attr.attr, + &sensor_dev_attr_pwm6_freq.dev_attr.attr, + &sensor_dev_attr_pwm6_enable.dev_attr.attr, NULL }; @@ -1649,27 +1658,45 @@ static const struct attribute_group dme1737_pwm_group[] = { * Their creation depends on the chip configuration which is determined during * module load. */ static struct attribute *dme1737_attr_fan1[] = { - SENSOR_DEV_ATTR_FAN_1TO4(1), + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, + &sensor_dev_attr_fan1_type.dev_attr.attr, NULL }; static struct attribute *dme1737_attr_fan2[] = { - SENSOR_DEV_ATTR_FAN_1TO4(2), + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, + &sensor_dev_attr_fan2_type.dev_attr.attr, NULL }; static struct attribute *dme1737_attr_fan3[] = { - SENSOR_DEV_ATTR_FAN_1TO4(3), + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan3_min.dev_attr.attr, + &sensor_dev_attr_fan3_alarm.dev_attr.attr, + &sensor_dev_attr_fan3_type.dev_attr.attr, NULL }; static struct attribute *dme1737_attr_fan4[] = { - SENSOR_DEV_ATTR_FAN_1TO4(4), + &sensor_dev_attr_fan4_input.dev_attr.attr, + &sensor_dev_attr_fan4_min.dev_attr.attr, + &sensor_dev_attr_fan4_alarm.dev_attr.attr, + &sensor_dev_attr_fan4_type.dev_attr.attr, NULL }; static struct attribute *dme1737_attr_fan5[] = { - SENSOR_DEV_ATTR_FAN_5TO6(5), + &sensor_dev_attr_fan5_input.dev_attr.attr, + &sensor_dev_attr_fan5_min.dev_attr.attr, + &sensor_dev_attr_fan5_alarm.dev_attr.attr, + &sensor_dev_attr_fan5_max.dev_attr.attr, NULL }; static struct attribute *dme1737_attr_fan6[] = { - SENSOR_DEV_ATTR_FAN_5TO6(6), + &sensor_dev_attr_fan6_input.dev_attr.attr, + &sensor_dev_attr_fan6_min.dev_attr.attr, + &sensor_dev_attr_fan6_alarm.dev_attr.attr, + &sensor_dev_attr_fan6_max.dev_attr.attr, NULL }; @@ -1686,13 +1713,22 @@ static const struct attribute_group dme1737_fan_group[] = { * writeable if the chip is *not* locked. Otherwise they stay read-only. */ static struct attribute *dme1737_attr_lock[] = { /* Temperatures */ - SENSOR_DEV_ATTR_TEMP_LOCK(1), - SENSOR_DEV_ATTR_TEMP_LOCK(2), - SENSOR_DEV_ATTR_TEMP_LOCK(3), + &sensor_dev_attr_temp1_offset.dev_attr.attr, + &sensor_dev_attr_temp2_offset.dev_attr.attr, + &sensor_dev_attr_temp3_offset.dev_attr.attr, /* Zones */ - SENSOR_DEV_ATTR_ZONE_LOCK(1), - SENSOR_DEV_ATTR_ZONE_LOCK(2), - SENSOR_DEV_ATTR_ZONE_LOCK(3), + &sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr, + &sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr, + &sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr, + &sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr, NULL }; @@ -1704,23 +1740,40 @@ static const struct attribute_group dme1737_lock_group = { * writeable if the chip is *not* locked and the respective PWM is available. * Otherwise they stay read-only. */ static struct attribute *dme1737_attr_pwm1_lock[] = { - SENSOR_DEV_ATTR_PWM_1TO3_LOCK(1), + &sensor_dev_attr_pwm1_freq.dev_attr.attr, + &sensor_dev_attr_pwm1_enable.dev_attr.attr, + &sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, NULL }; static struct attribute *dme1737_attr_pwm2_lock[] = { - SENSOR_DEV_ATTR_PWM_1TO3_LOCK(2), + &sensor_dev_attr_pwm2_freq.dev_attr.attr, + &sensor_dev_attr_pwm2_enable.dev_attr.attr, + &sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, NULL }; static struct attribute *dme1737_attr_pwm3_lock[] = { - SENSOR_DEV_ATTR_PWM_1TO3_LOCK(3), + &sensor_dev_attr_pwm3_freq.dev_attr.attr, + &sensor_dev_attr_pwm3_enable.dev_attr.attr, + &sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, NULL }; static struct attribute *dme1737_attr_pwm5_lock[] = { - SENSOR_DEV_ATTR_PWM_5TO6_LOCK(5), + &sensor_dev_attr_pwm5.dev_attr.attr, + &sensor_dev_attr_pwm5_freq.dev_attr.attr, NULL }; static struct attribute *dme1737_attr_pwm6_lock[] = { - SENSOR_DEV_ATTR_PWM_5TO6_LOCK(6), + &sensor_dev_attr_pwm6.dev_attr.attr, + &sensor_dev_attr_pwm6_freq.dev_attr.attr, NULL }; -- cgit v1.2.3 From 92430b6feb19aba043171ff3094535b598052901 Mon Sep 17 00:00:00 2001 From: Juerg Haefliger Date: Thu, 3 Apr 2008 21:34:19 -0700 Subject: hwmon: (dme1737) probe all addresses This patch adds a module load parameter to enable probing of non-standard LPC addresses 0x162e and 0x164e when scanning for supported ISA chips. Signed-Off-By: Juerg Haefliger Acked-by: Jean Delvare Signed-off-by: Mark M. Hoffman --- drivers/hwmon/dme1737.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index c24b5b370da..5a3d41fbdb3 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -48,6 +48,11 @@ static unsigned short force_id; module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); +static int probe_all_addr; +module_param(probe_all_addr, bool, 0); +MODULE_PARM_DESC(probe_all_addr, "Include probing of non-standard LPC " + "addresses"); + /* Addresses to scan */ static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END}; @@ -2430,7 +2435,10 @@ static int __init dme1737_init(void) } if (dme1737_isa_detect(0x2e, &addr) && - dme1737_isa_detect(0x4e, &addr)) { + dme1737_isa_detect(0x4e, &addr) && + (!probe_all_addr || + (dme1737_isa_detect(0x162e, &addr) && + dme1737_isa_detect(0x164e, &addr)))) { /* Return 0 if we didn't find an ISA device */ return 0; } -- cgit v1.2.3 From f994fb23d3c63dffc8127f227f3e0c530e3e4fd6 Mon Sep 17 00:00:00 2001 From: Juerg Haefliger Date: Tue, 25 Mar 2008 21:49:15 -0700 Subject: hwmon: (dme1737) fix voltage scaling This patch fixes a voltage scaling issue for the sch311x device. Signed-Off-By: Juerg Haefliger Acked-by: Jean Delvare Signed-off-by: Mark M. Hoffman --- drivers/hwmon/dme1737.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index 5a3d41fbdb3..5e2cf0aef48 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -181,6 +181,7 @@ struct dme1737_data { int valid; /* !=0 if following fields are valid */ unsigned long last_update; /* in jiffies */ unsigned long last_vbat; /* in jiffies */ + enum chips type; u8 vid; u8 pwm_rr_en; @@ -215,20 +216,27 @@ struct dme1737_data { }; /* Nominal voltage values */ -static const int IN_NOMINAL[] = {5000, 2250, 3300, 5000, 12000, 3300, 3300}; +static const int IN_NOMINAL_DME1737[] = {5000, 2250, 3300, 5000, 12000, 3300, + 3300}; +static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300, + 3300}; +#define IN_NOMINAL(ix, type) (((type) == dme1737) ? \ + IN_NOMINAL_DME1737[(ix)] : \ + IN_NOMINAL_SCH311x[(ix)]) /* Voltage input * Voltage inputs have 16 bits resolution, limit values have 8 bits * resolution. */ -static inline int IN_FROM_REG(int reg, int ix, int res) +static inline int IN_FROM_REG(int reg, int ix, int res, int type) { - return (reg * IN_NOMINAL[ix] + (3 << (res - 3))) / (3 << (res - 2)); + return (reg * IN_NOMINAL(ix, type) + (3 << (res - 3))) / + (3 << (res - 2)); } -static inline int IN_TO_REG(int val, int ix) +static inline int IN_TO_REG(int val, int ix, int type) { - return SENSORS_LIMIT((val * 192 + IN_NOMINAL[ix] / 2) / - IN_NOMINAL[ix], 0, 255); + return SENSORS_LIMIT((val * 192 + IN_NOMINAL(ix, type) / 2) / + IN_NOMINAL(ix, type), 0, 255); } /* Temperature input @@ -727,13 +735,13 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr, switch (fn) { case SYS_IN_INPUT: - res = IN_FROM_REG(data->in[ix], ix, 16); + res = IN_FROM_REG(data->in[ix], ix, 16, data->type); break; case SYS_IN_MIN: - res = IN_FROM_REG(data->in_min[ix], ix, 8); + res = IN_FROM_REG(data->in_min[ix], ix, 8, data->type); break; case SYS_IN_MAX: - res = IN_FROM_REG(data->in_max[ix], ix, 8); + res = IN_FROM_REG(data->in_max[ix], ix, 8, data->type); break; case SYS_IN_ALARM: res = (data->alarms >> DME1737_BIT_ALARM_IN[ix]) & 0x01; @@ -760,12 +768,12 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); switch (fn) { case SYS_IN_MIN: - data->in_min[ix] = IN_TO_REG(val, ix); + data->in_min[ix] = IN_TO_REG(val, ix, data->type); dme1737_write(client, DME1737_REG_IN_MIN(ix), data->in_min[ix]); break; case SYS_IN_MAX: - data->in_max[ix] = IN_TO_REG(val, ix); + data->in_max[ix] = IN_TO_REG(val, ix, data->type); dme1737_write(client, DME1737_REG_IN_MAX(ix), data->in_max[ix]); break; @@ -2167,6 +2175,7 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address, kind = dme1737; name = "dme1737"; + data->type = kind; /* Fill in the remaining client fields and put it into the global * list */ @@ -2359,6 +2368,7 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev) err = -ENODEV; goto exit_kfree; } + data->type = -1; /* Fill in the remaining client fields and initialize the mutex */ strlcpy(client->name, "sch311x", I2C_NAME_SIZE); -- cgit v1.2.3 From 9d3e19afd35907bf58b205096cd33e97df8fb6a5 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 26 Apr 2008 16:28:27 +0200 Subject: hwmon: (adt7473) Remove unused defines All the *_MAX_ADDR defines are never used, so remove them. The number of registers of each type is already expressed by the *_COUNT defines. Signed-off-by: Jean Delvare Acked-by: Darrick J. Wong Signed-off-by: Mark M. Hoffman --- drivers/hwmon/adt7473.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/adt7473.c b/drivers/hwmon/adt7473.c index 93dbf5e7ff8..7ecebfd404e 100644 --- a/drivers/hwmon/adt7473.c +++ b/drivers/hwmon/adt7473.c @@ -39,32 +39,20 @@ I2C_CLIENT_INSMOD_1(adt7473); #define ADT7473_REG_BASE_ADDR 0x20 #define ADT7473_REG_VOLT_BASE_ADDR 0x21 -#define ADT7473_REG_VOLT_MAX_ADDR 0x22 #define ADT7473_REG_VOLT_MIN_BASE_ADDR 0x46 -#define ADT7473_REG_VOLT_MIN_MAX_ADDR 0x49 #define ADT7473_REG_TEMP_BASE_ADDR 0x25 -#define ADT7473_REG_TEMP_MAX_ADDR 0x27 #define ADT7473_REG_TEMP_LIMITS_BASE_ADDR 0x4E -#define ADT7473_REG_TEMP_LIMITS_MAX_ADDR 0x53 #define ADT7473_REG_TEMP_TMIN_BASE_ADDR 0x67 -#define ADT7473_REG_TEMP_TMIN_MAX_ADDR 0x69 #define ADT7473_REG_TEMP_TMAX_BASE_ADDR 0x6A -#define ADT7473_REG_TEMP_TMAX_MAX_ADDR 0x6C #define ADT7473_REG_FAN_BASE_ADDR 0x28 -#define ADT7473_REG_FAN_MAX_ADDR 0x2F #define ADT7473_REG_FAN_MIN_BASE_ADDR 0x54 -#define ADT7473_REG_FAN_MIN_MAX_ADDR 0x5B #define ADT7473_REG_PWM_BASE_ADDR 0x30 -#define ADT7473_REG_PWM_MAX_ADDR 0x32 #define ADT7473_REG_PWM_MIN_BASE_ADDR 0x64 -#define ADT7473_REG_PWM_MIN_MAX_ADDR 0x66 #define ADT7473_REG_PWM_MAX_BASE_ADDR 0x38 -#define ADT7473_REG_PWM_MAX_MAX_ADDR 0x3A #define ADT7473_REG_PWM_BHVR_BASE_ADDR 0x5C -#define ADT7473_REG_PWM_BHVR_MAX_ADDR 0x5E #define ADT7473_PWM_BHVR_MASK 0xE0 #define ADT7473_PWM_BHVR_SHIFT 5 @@ -102,7 +90,6 @@ I2C_CLIENT_INSMOD_1(adt7473); #define ADT7473_FAN4_ALARM 0x20 #define ADT7473_R1T_SHORT 0x40 #define ADT7473_R2T_SHORT 0x80 -#define ADT7473_REG_MAX_ADDR 0x80 #define ALARM2(x) ((x) << 8) -- cgit v1.2.3 From 321c4138573da888ca30a387e9973f690c217e9e Mon Sep 17 00:00:00 2001 From: "Mark M. Hoffman" Date: Mon, 26 May 2008 15:09:36 -0400 Subject: hwmon: (adt7473) clarify an awkward bit of code Signed-off-by: Mark M. Hoffman Acked-by: Jean Delvare --- drivers/hwmon/adt7473.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/adt7473.c b/drivers/hwmon/adt7473.c index 7ecebfd404e..0cd6c720a85 100644 --- a/drivers/hwmon/adt7473.c +++ b/drivers/hwmon/adt7473.c @@ -559,10 +559,9 @@ static ssize_t set_max_duty_at_crit(struct device *dev, struct i2c_client *client = to_i2c_client(dev); struct adt7473_data *data = i2c_get_clientdata(client); int temp = simple_strtol(buf, NULL, 10); - temp = temp && 0xFF; mutex_lock(&data->lock); - data->max_duty_at_overheat = temp; + data->max_duty_at_overheat = !!temp; reg = i2c_smbus_read_byte_data(client, ADT7473_REG_CFG4); if (temp) reg |= ADT7473_CFG4_MAX_DUTY_AT_OVT; -- cgit v1.2.3 From 01a52397e95a8532c59506691759dba9262d6be7 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 21 Apr 2008 12:10:53 -0700 Subject: hwmon: (lm75) cleanup/reorg Minor cleanup and reorg of the lm75 code. - Kconfig provides a larger list of lm75-compatible chips - A top comment now says what the driver does (!) ... as in, just what sort of sensor is this?? - Section comments now delineate the various sections of the driver: hwmon attributes, driver binding, register access, module glue. One driver binding function moved out of the attribute section, as did the driver struct itself. - Minor tweaks to legacy probe logic: correct a comment, and remove a pointless variable. - Whitespace, linelength, and comment fixes. This patch should include no functional changes. It's preparation for adding new-style (driver model) I2C driver binding. Signed-off-by: David Brownell Acked-by: Jean Delvare Acked-by: Laurent Pinchart Signed-off-by: Mark M. Hoffman --- drivers/hwmon/Kconfig | 20 ++++++++---- drivers/hwmon/lm75.c | 90 +++++++++++++++++++++++++++++---------------------- 2 files changed, 64 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 00ff5334849..86289c283dc 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -394,13 +394,19 @@ config SENSORS_LM75 tristate "National Semiconductor LM75 and compatibles" depends on I2C help - If you say yes here you get support for National Semiconductor LM75 - sensor chips and clones: Dallas Semiconductor DS75 and DS1775 (in - 9-bit precision mode), and TelCom (now Microchip) TCN75. - - The DS75 and DS1775 in 10- to 12-bit precision modes will require - a force module parameter. The driver will not handle the extra - precision anyhow. + If you say yes here you get support for one common type of + temperature sensor chip, with models including: + + - Dallas Semiconductor DS75 and DS1775 + - Maxim MAX6625 and MAX6626 + - Microchip MCP980x + - National Semiconductor LM75 + - NXP's LM75A + - ST Microelectronics STDS75 + - TelCom (now Microchip) TCN75 + - Texas Instruments TMP100, TMP101, TMP75, TMP175, TMP275 + + Most of these chips will require a "force" module parameter. This driver can also be built as a module. If so, the module will be called lm75. diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index de698dc7302..25ed2658410 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -30,14 +30,19 @@ #include "lm75.h" -/* Addresses to scan */ +/* + * This driver handles the LM75 and compatible digital temperature sensors. + * Compatibles include at least the DS75, DS1775, MCP980x, STDS75, TCN75, + * TMP100, TMP101, TMP75, TMP175, and TMP275. + */ + +/* Addresses scanned by legacy style driver binding */ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; -/* Insmod parameters */ +/* Insmod parameters (only for legacy style driver binding) */ I2C_CLIENT_INSMOD_1(lm75); -/* Many LM75 constants specified below */ /* The LM75 registers */ #define LM75_REG_CONF 0x01 @@ -50,9 +55,9 @@ static const u8 LM75_REG_TEMP[3] = { /* Each client has this additional data */ struct lm75_data { struct i2c_client client; - struct device *hwmon_dev; + struct device *hwmon_dev; struct mutex update_lock; - char valid; /* !=0 if following fields are valid */ + char valid; /* !=0 if registers are valid */ unsigned long last_updated; /* In jiffies */ u16 temp[3]; /* Register values, 0 = input @@ -60,23 +65,15 @@ struct lm75_data { 2 = hyst */ }; -static int lm75_attach_adapter(struct i2c_adapter *adapter); -static int lm75_detect(struct i2c_adapter *adapter, int address, int kind); static void lm75_init_client(struct i2c_client *client); -static int lm75_detach_client(struct i2c_client *client); static int lm75_read_value(struct i2c_client *client, u8 reg); static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value); static struct lm75_data *lm75_update_device(struct device *dev); -/* This is the driver that will be inserted */ -static struct i2c_driver lm75_driver = { - .driver = { - .name = "lm75", - }, - .attach_adapter = lm75_attach_adapter, - .detach_client = lm75_detach_client, -}; +/*-----------------------------------------------------------------------*/ + +/* sysfs attributes for hwmon */ static ssize_t show_temp(struct device *dev, struct device_attribute *da, char *buf) @@ -109,13 +106,6 @@ static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp, set_temp, 2); static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); -static int lm75_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_probe(adapter, &addr_data, lm75_detect); -} - static struct attribute *lm75_attributes[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, @@ -128,6 +118,12 @@ static const struct attribute_group lm75_group = { .attrs = lm75_attributes, }; +/*-----------------------------------------------------------------------*/ + +/* "Legacy" I2C driver binding */ + +static struct i2c_driver lm75_driver; + /* This function is called by i2c_probe */ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) { @@ -135,15 +131,14 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) struct i2c_client *new_client; struct lm75_data *data; int err = 0; - const char *name = ""; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) goto exit; - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm75_{read,write}_value. */ + /* OK. For now, we presume we have a valid address. We create the + client structure, even though there may be no sensor present. + But it allows us to use i2c_smbus_read_*_data() calls. */ if (!(data = kzalloc(sizeof(struct lm75_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; @@ -174,17 +169,17 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) || i2c_smbus_read_word_data(new_client, 5) != hyst || i2c_smbus_read_word_data(new_client, 6) != hyst || i2c_smbus_read_word_data(new_client, 7) != hyst) - goto exit_free; + goto exit_free; os = i2c_smbus_read_word_data(new_client, 3); if (i2c_smbus_read_word_data(new_client, 4) != os || i2c_smbus_read_word_data(new_client, 5) != os || i2c_smbus_read_word_data(new_client, 6) != os || i2c_smbus_read_word_data(new_client, 7) != os) - goto exit_free; + goto exit_free; /* Unused bits */ if (conf & 0xe0) - goto exit_free; + goto exit_free; /* Addresses cycling */ for (i = 8; i < 0xff; i += 8) @@ -194,16 +189,10 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_free; } - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = lm75; - - if (kind == lm75) { - name = "lm75"; - } + /* NOTE: we treat "force=..." and "force_lm75=..." the same. */ + strlcpy(new_client->name, "lm75", I2C_NAME_SIZE); /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); data->valid = 0; mutex_init(&data->update_lock); @@ -213,7 +202,7 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) /* Initialize the LM75 chip */ lm75_init_client(new_client); - + /* Register sysfs hooks */ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm75_group))) goto exit_detach; @@ -236,6 +225,13 @@ exit: return err; } +static int lm75_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_probe(adapter, &addr_data, lm75_detect); +} + static int lm75_detach_client(struct i2c_client *client) { struct lm75_data *data = i2c_get_clientdata(client); @@ -246,6 +242,18 @@ static int lm75_detach_client(struct i2c_client *client) return 0; } +static struct i2c_driver lm75_driver = { + .driver = { + .name = "lm75", + }, + .attach_adapter = lm75_attach_adapter, + .detach_client = lm75_detach_client, +}; + +/*-----------------------------------------------------------------------*/ + +/* register access */ + /* All registers are word-sized, except for the configuration register. LM75 uses a high-byte first convention, which is exactly opposite to the SMBus standard. */ @@ -309,6 +317,10 @@ static struct lm75_data *lm75_update_device(struct device *dev) return data; } +/*-----------------------------------------------------------------------*/ + +/* module glue */ + static int __init sensors_lm75_init(void) { return i2c_add_driver(&lm75_driver); -- cgit v1.2.3 From 9ebd3d822efeca2e73565516a80373c76ce3fa12 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 3 May 2008 19:33:15 -0700 Subject: hwmon: (lm75) add new-style driver binding More LM75 updates: - Teach the LM75 driver to use new-style driver binding: * Create a second driver struct, using new-style driver binding methods cribbed from the legacy code. * Add a MODULE_DEVICE_TABLE (for "newER-style binding") * The legacy probe logic delegates its work to this new code. * The legacy driver now uses the name "lm75_legacy". - More careful initialization. Chips are put into 9-bit mode so the current interconversion routines will never fail. - Save the original chip configuration, and restore it on exit. (Among other things, this normally turns off the mode where the chip is constantly sampling ... and thus saves power.) So the new-style code should catch all chips that boards declare, while the legacy code catches others. This particular coexistence strategy may need some work yet ... legacy modes might best be set up explicitly by some tool not unlike "sensors-detect". (Or else completely eradicated...) Signed-off-by: David Brownell Acked-by: Jean Delvare Signed-off-by: Mark M. Hoffman --- drivers/hwmon/Kconfig | 7 +- drivers/hwmon/lm75.c | 206 ++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 165 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 86289c283dc..c882fd05cf2 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -406,7 +406,12 @@ config SENSORS_LM75 - TelCom (now Microchip) TCN75 - Texas Instruments TMP100, TMP101, TMP75, TMP175, TMP275 - Most of these chips will require a "force" module parameter. + This driver supports driver model based binding through board + specific I2C device tables. + + It also supports the "legacy" style of driver binding. To use + that with some chips which don't replicate LM75 quirks exactly, + you may need the "force" module parameter. This driver can also be built as a module. If so, the module will be called lm75. diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 25ed2658410..7880c273c2c 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -32,10 +32,28 @@ /* * This driver handles the LM75 and compatible digital temperature sensors. - * Compatibles include at least the DS75, DS1775, MCP980x, STDS75, TCN75, - * TMP100, TMP101, TMP75, TMP175, and TMP275. + * Only types which are _not_ listed in I2C_CLIENT_INSMOD_*() need to be + * listed here. We start at 9 since I2C_CLIENT_INSMOD_*() currently allow + * definition of up to 8 chip types (plus zero). */ +enum lm75_type { /* keep sorted in alphabetical order */ + ds1775 = 9, + ds75, + /* lm75 -- in I2C_CLIENT_INSMOD_1() */ + lm75a, + max6625, + max6626, + mcp980x, + stds75, + tcn75, + tmp100, + tmp101, + tmp175, + tmp275, + tmp75, +}; + /* Addresses scanned by legacy style driver binding */ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; @@ -54,9 +72,10 @@ static const u8 LM75_REG_TEMP[3] = { /* Each client has this additional data */ struct lm75_data { - struct i2c_client client; + struct i2c_client *client; struct device *hwmon_dev; struct mutex update_lock; + u8 orig_conf; char valid; /* !=0 if registers are valid */ unsigned long last_updated; /* In jiffies */ u16 temp[3]; /* Register values, @@ -65,7 +84,6 @@ struct lm75_data { 2 = hyst */ }; -static void lm75_init_client(struct i2c_client *client); static int lm75_read_value(struct i2c_client *client, u8 reg); static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value); static struct lm75_data *lm75_update_device(struct device *dev); @@ -120,16 +138,124 @@ static const struct attribute_group lm75_group = { /*-----------------------------------------------------------------------*/ +/* "New style" I2C driver binding -- following the driver model */ + +static int +lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct lm75_data *data; + int status; + u8 set_mask, clr_mask; + int new; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) + return -EIO; + + data = kzalloc(sizeof(struct lm75_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + i2c_set_clientdata(client, data); + + data->client = client; + mutex_init(&data->update_lock); + + /* Set to LM75 resolution (9 bits, 1/2 degree C) and range. + * Then tweak to be more precise when appropriate. + */ + set_mask = 0; + clr_mask = (1 << 0) /* continuous conversions */ + | (1 << 6) | (1 << 5); /* 9-bit mode */ + + /* configure as specified */ + status = lm75_read_value(client, LM75_REG_CONF); + if (status < 0) { + dev_dbg(&client->dev, "Can't read config? %d\n", status); + goto exit_free; + } + data->orig_conf = status; + new = status & ~clr_mask; + new |= set_mask; + if (status != new) + lm75_write_value(client, LM75_REG_CONF, new); + dev_dbg(&client->dev, "Config %02x\n", new); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &lm75_group); + if (status) + goto exit_free; + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: sensor '%s'\n", + data->hwmon_dev->bus_id, client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &lm75_group); +exit_free: + i2c_set_clientdata(client, NULL); + kfree(data); + return status; +} + +static int lm75_remove(struct i2c_client *client) +{ + struct lm75_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &lm75_group); + lm75_write_value(client, LM75_REG_CONF, data->orig_conf); + i2c_set_clientdata(client, NULL); + kfree(data); + return 0; +} + +static const struct i2c_device_id lm75_ids[] = { + { "ds1775", ds1775, }, + { "ds75", ds75, }, + { "lm75", lm75, }, + { "lm75a", lm75a, }, + { "max6625", max6625, }, + { "max6626", max6626, }, + { "mcp980x", mcp980x, }, + { "stds75", stds75, }, + { "tcn75", tcn75, }, + { "tmp100", tmp100, }, + { "tmp101", tmp101, }, + { "tmp175", tmp175, }, + { "tmp275", tmp275, }, + { "tmp75", tmp75, }, + { /* LIST END */ } +}; +MODULE_DEVICE_TABLE(i2c, lm75_ids); + +static struct i2c_driver lm75_driver = { + .driver = { + .name = "lm75", + }, + .probe = lm75_probe, + .remove = lm75_remove, + .id_table = lm75_ids, +}; + +/*-----------------------------------------------------------------------*/ + /* "Legacy" I2C driver binding */ -static struct i2c_driver lm75_driver; +static struct i2c_driver lm75_legacy_driver; /* This function is called by i2c_probe */ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) { int i; struct i2c_client *new_client; - struct lm75_data *data; int err = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | @@ -139,16 +265,15 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) /* OK. For now, we presume we have a valid address. We create the client structure, even though there may be no sensor present. But it allows us to use i2c_smbus_read_*_data() calls. */ - if (!(data = kzalloc(sizeof(struct lm75_data), GFP_KERNEL))) { + new_client = kzalloc(sizeof *new_client, GFP_KERNEL); + if (!new_client) { err = -ENOMEM; goto exit; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; - new_client->driver = &lm75_driver; + new_client->driver = &lm75_legacy_driver; new_client->flags = 0; /* Now, we do the remaining detection. There is no identification- @@ -189,38 +314,26 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_free; } - /* NOTE: we treat "force=..." and "force_lm75=..." the same. */ + /* NOTE: we treat "force=..." and "force_lm75=..." the same. + * Only new-style driver binding distinguishes chip types. + */ strlcpy(new_client->name, "lm75", I2C_NAME_SIZE); - /* Fill in the remaining client fields and put it into the global list */ - data->valid = 0; - mutex_init(&data->update_lock); - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) + err = i2c_attach_client(new_client); + if (err) goto exit_free; - /* Initialize the LM75 chip */ - lm75_init_client(new_client); - - /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &lm75_group))) + err = lm75_probe(new_client, NULL); + if (err < 0) goto exit_detach; - data->hwmon_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } - return 0; -exit_remove: - sysfs_remove_group(&new_client->dev.kobj, &lm75_group); exit_detach: i2c_detach_client(new_client); exit_free: - kfree(data); + kfree(new_client); exit: return err; } @@ -234,17 +347,15 @@ static int lm75_attach_adapter(struct i2c_adapter *adapter) static int lm75_detach_client(struct i2c_client *client) { - struct lm75_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm75_group); + lm75_remove(client); i2c_detach_client(client); - kfree(data); + kfree(client); return 0; } -static struct i2c_driver lm75_driver = { +static struct i2c_driver lm75_legacy_driver = { .driver = { - .name = "lm75", + .name = "lm75_legacy", }, .attach_adapter = lm75_attach_adapter, .detach_client = lm75_detach_client, @@ -276,16 +387,6 @@ static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) return i2c_smbus_write_word_data(client, reg, swab16(value)); } -static void lm75_init_client(struct i2c_client *client) -{ - int reg; - - /* Enable if in shutdown mode */ - reg = lm75_read_value(client, LM75_REG_CONF); - if (reg >= 0 && (reg & 0x01)) - lm75_write_value(client, LM75_REG_CONF, reg & 0xfe); -} - static struct lm75_data *lm75_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -323,11 +424,22 @@ static struct lm75_data *lm75_update_device(struct device *dev) static int __init sensors_lm75_init(void) { - return i2c_add_driver(&lm75_driver); + int status; + + status = i2c_add_driver(&lm75_driver); + if (status < 0) + return status; + + status = i2c_add_driver(&lm75_legacy_driver); + if (status < 0) + i2c_del_driver(&lm75_driver); + + return status; } static void __exit sensors_lm75_exit(void) { + i2c_del_driver(&lm75_legacy_driver); i2c_del_driver(&lm75_driver); } -- cgit v1.2.3 From 1f44809ac3d7a3fc977684dc3a95fa221f33fc15 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 29 Apr 2008 14:03:37 +0200 Subject: hwmon: (lm85) Coding-style cleanups Fix most style issues reported by checkpatch, including: * Trailing, missing and extra whitespace * Extra parentheses, curly braces and semi-colons * Broken indentation * Lines too long I verified that the generated code is the same before and after these changes. Signed-off-by: Jean Delvare Acked-by: Juerg Haefliger Signed-off-by: Mark M. Hoffman --- drivers/hwmon/lm85.c | 505 ++++++++++++++++++++++++++------------------------- 1 file changed, 255 insertions(+), 250 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index ee5eca1c192..0c0fede8dde 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -1,7 +1,7 @@ /* lm85.c - Part of lm_sensors, Linux kernel modules for hardware monitoring - Copyright (c) 1998, 1999 Frodo Looijaard + Copyright (c) 1998, 1999 Frodo Looijaard Copyright (c) 2002, 2003 Philip Pokorny Copyright (c) 2003 Margit Schubert-While Copyright (c) 2004 Justin Thiessen @@ -51,8 +51,8 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102); #define LM85_REG_TEMP_MAX(nr) (0x4f + (nr) * 2) /* Fan speeds are LSB, MSB (2 bytes) */ -#define LM85_REG_FAN(nr) (0x28 + (nr) *2) -#define LM85_REG_FAN_MIN(nr) (0x54 + (nr) *2) +#define LM85_REG_FAN(nr) (0x28 + (nr) * 2) +#define LM85_REG_FAN_MIN(nr) (0x54 + (nr) * 2) #define LM85_REG_PWM(nr) (0x30 + (nr)) @@ -68,7 +68,7 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102); #define LM85_DEVICE_ADX 0x27 #define LM85_COMPANY_NATIONAL 0x01 #define LM85_COMPANY_ANALOG_DEV 0x41 -#define LM85_COMPANY_SMSC 0x5c +#define LM85_COMPANY_SMSC 0x5c #define LM85_VERSTEP_VMASK 0xf0 #define LM85_VERSTEP_GENERIC 0x60 #define LM85_VERSTEP_LM85C 0x60 @@ -115,34 +115,34 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102); #define EMC6D100_REG_ALARM3 0x7d /* IN5, IN6 and IN7 */ -#define EMC6D100_REG_IN(nr) (0x70 + ((nr)-5)) -#define EMC6D100_REG_IN_MIN(nr) (0x73 + ((nr)-5) * 2) -#define EMC6D100_REG_IN_MAX(nr) (0x74 + ((nr)-5) * 2) +#define EMC6D100_REG_IN(nr) (0x70 + ((nr) - 5)) +#define EMC6D100_REG_IN_MIN(nr) (0x73 + ((nr) - 5) * 2) +#define EMC6D100_REG_IN_MAX(nr) (0x74 + ((nr) - 5) * 2) #define EMC6D102_REG_EXTEND_ADC1 0x85 #define EMC6D102_REG_EXTEND_ADC2 0x86 #define EMC6D102_REG_EXTEND_ADC3 0x87 #define EMC6D102_REG_EXTEND_ADC4 0x88 -/* Conversions. Rounding and limit checking is only done on the TO_REG +/* Conversions. Rounding and limit checking is only done on the TO_REG variants. Note that you should be a bit careful with which arguments these macros are called: arguments may be evaluated more than once. */ /* IN are scaled acording to built-in resistors */ static int lm85_scaling[] = { /* .001 Volts */ - 2500, 2250, 3300, 5000, 12000, - 3300, 1500, 1800 /*EMC6D100*/ - }; -#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) + 2500, 2250, 3300, 5000, 12000, + 3300, 1500, 1800 /*EMC6D100*/ +}; +#define SCALE(val, from, to) (((val) * (to) + ((from) / 2)) / (from)) -#define INS_TO_REG(n,val) \ - SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255) +#define INS_TO_REG(n, val) \ + SENSORS_LIMIT(SCALE(val, lm85_scaling[n], 192), 0, 255) -#define INSEXT_FROM_REG(n,val,ext) \ +#define INSEXT_FROM_REG(n, val, ext) \ SCALE(((val) << 4) + (ext), 192 << 4, lm85_scaling[n]) -#define INS_FROM_REG(n,val) SCALE((val), 192, lm85_scaling[n]) +#define INS_FROM_REG(n, val) SCALE((val), 192, lm85_scaling[n]) /* FAN speed is measured using 90kHz clock */ static inline u16 FAN_TO_REG(unsigned long val) @@ -151,16 +151,17 @@ static inline u16 FAN_TO_REG(unsigned long val) return 0xffff; return SENSORS_LIMIT(5400000 / val, 1, 0xfffe); } -#define FAN_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:5400000/(val)) +#define FAN_FROM_REG(val) ((val) == 0 ? -1 : (val) == 0xffff ? 0 : \ + 5400000 / (val)) /* Temperature is reported in .001 degC increments */ #define TEMP_TO_REG(val) \ - SENSORS_LIMIT(SCALE(val,1000,1),-127,127) -#define TEMPEXT_FROM_REG(val,ext) \ + SENSORS_LIMIT(SCALE(val, 1000, 1), -127, 127) +#define TEMPEXT_FROM_REG(val, ext) \ SCALE(((val) << 4) + (ext), 16, 1000) #define TEMP_FROM_REG(val) ((val) * 1000) -#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) +#define PWM_TO_REG(val) SENSORS_LIMIT(val, 0, 255) #define PWM_FROM_REG(val) (val) @@ -183,17 +184,17 @@ static inline u16 FAN_TO_REG(unsigned long val) */ /* These are the zone temperature range encodings in .001 degree C */ -static int lm85_range_map[] = { - 2000, 2500, 3300, 4000, 5000, 6600, - 8000, 10000, 13300, 16000, 20000, 26600, - 32000, 40000, 53300, 80000 - }; -static int RANGE_TO_REG( int range ) +static int lm85_range_map[] = { + 2000, 2500, 3300, 4000, 5000, 6600, 8000, 10000, + 13300, 16000, 20000, 26600, 32000, 40000, 53300, 80000 +}; + +static int RANGE_TO_REG(int range) { int i; if (range >= lm85_range_map[15]) - return 15 ; + return 15; /* Find the closest match */ for (i = 14; i >= 0; --i) { @@ -207,7 +208,7 @@ static int RANGE_TO_REG( int range ) return 0; } -#define RANGE_FROM_REG(val) (lm85_range_map[(val)&0x0f]) +#define RANGE_FROM_REG(val) lm85_range_map[(val) & 0x0f] /* These are the Acoustic Enhancement, or Temperature smoothing encodings * NOTE: The enable/disable bit is INCLUDED in these encodings as the @@ -216,19 +217,21 @@ static int RANGE_TO_REG( int range ) */ /* These are the PWM frequency encodings */ static int lm85_freq_map[] = { /* .1 Hz */ - 100, 150, 230, 300, 380, 470, 620, 940 - }; -static int FREQ_TO_REG( int freq ) + 100, 150, 230, 300, 380, 470, 620, 940 +}; + +static int FREQ_TO_REG(int freq) { int i; - if( freq >= lm85_freq_map[7] ) { return 7 ; } - for( i = 0 ; i < 7 ; ++i ) - if( freq <= lm85_freq_map[i] ) - break ; - return( i & 0x07 ); + if (freq >= lm85_freq_map[7]) + return 7; + for (i = 0; i < 7; ++i) + if (freq <= lm85_freq_map[i]) + break; + return i & 0x07; } -#define FREQ_FROM_REG(val) (lm85_freq_map[(val)&0x07]) +#define FREQ_FROM_REG(val) lm85_freq_map[(val) & 0x07] /* Since we can't use strings, I'm abusing these numbers * to stand in for the following meanings: @@ -243,29 +246,29 @@ static int FREQ_TO_REG( int freq ) */ static int lm85_zone_map[] = { 1, 2, 3, -1, 0, 23, 123, -2 }; -#define ZONE_FROM_REG(val) (lm85_zone_map[((val)>>5)&0x07]) +#define ZONE_FROM_REG(val) lm85_zone_map[((val) >> 5) & 0x07] -static int ZONE_TO_REG( int zone ) +static int ZONE_TO_REG(int zone) { int i; - for( i = 0 ; i <= 7 ; ++i ) - if( zone == lm85_zone_map[i] ) - break ; - if( i > 7 ) /* Not found. */ + for (i = 0; i <= 7; ++i) + if (zone == lm85_zone_map[i]) + break; + if (i > 7) /* Not found. */ i = 3; /* Always 100% */ - return( (i & 0x07)<<5 ); + return (i & 0x07) << 5; } -#define HYST_TO_REG(val) (SENSORS_LIMIT(((val)+500)/1000,0,15)) -#define HYST_FROM_REG(val) ((val)*1000) +#define HYST_TO_REG(val) SENSORS_LIMIT(((val) + 500) / 1000, 0, 15) +#define HYST_FROM_REG(val) ((val) * 1000) -#define OFFSET_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127)) -#define OFFSET_FROM_REG(val) ((val)*25) +#define OFFSET_TO_REG(val) SENSORS_LIMIT((val) / 25, -127, 127) +#define OFFSET_FROM_REG(val) ((val) * 25) -#define PPR_MASK(fan) (0x03<<(fan *2)) -#define PPR_TO_REG(val,fan) (SENSORS_LIMIT((val)-1,0,3)<<(fan *2)) -#define PPR_FROM_REG(val,fan) ((((val)>>(fan * 2))&0x03)+1) +#define PPR_MASK(fan) (0x03 << ((fan) * 2)) +#define PPR_TO_REG(val, fan) (SENSORS_LIMIT((val) - 1, 0, 3) << ((fan) * 2)) +#define PPR_FROM_REG(val, fan) ((((val) >> ((fan) * 2)) & 0x03) + 1) /* Chip sampling rates * @@ -292,11 +295,11 @@ struct lm85_zone { u8 hyst; /* Low limit hysteresis. (0-15) */ u8 range; /* Temp range, encoded */ s8 critical; /* "All fans ON" temp limit */ - u8 off_desired; /* Actual "off" temperature specified. Preserved + u8 off_desired; /* Actual "off" temperature specified. Preserved * to prevent "drift" as other autofan control * values change. */ - u8 max_desired; /* Actual "max" temperature specified. Preserved + u8 max_desired; /* Actual "max" temperature specified. Preserved * to prevent "drift" as other autofan control * values change. */ @@ -375,7 +378,7 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr, { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr]) ); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr])); } static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, @@ -383,7 +386,7 @@ static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr]) ); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr])); } static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, @@ -414,7 +417,8 @@ show_fan_offset(4); /* vid, vrm, alarms */ -static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, + char *buf) { struct lm85_data *data = lm85_update_device(dev); int vid; @@ -432,13 +436,15 @@ static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, c static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); -static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, + char *buf) { struct lm85_data *data = dev_get_drvdata(dev); return sprintf(buf, "%ld\n", (long) data->vrm); } -static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct lm85_data *data = dev_get_drvdata(dev); data->vrm = simple_strtoul(buf, NULL, 10); @@ -447,7 +453,8 @@ static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); -static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarms_reg(struct device *dev, struct device_attribute + *attr, char *buf) { struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%u\n", data->alarms); @@ -488,7 +495,7 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm[nr]) ); + return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr])); } static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, @@ -581,17 +588,16 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr, { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - return sprintf( buf, "%d\n", INSEXT_FROM_REG(nr, - data->in[nr], - data->in_ext[nr])); + return sprintf(buf, "%d\n", INSEXT_FROM_REG(nr, data->in[nr], + data->in_ext[nr])); } -static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, +static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, char *buf) { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr]) ); + return sprintf(buf, "%d\n", INS_FROM_REG(nr, data->in_min[nr])); } static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, @@ -614,7 +620,7 @@ static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr]) ); + return sprintf(buf, "%d\n", INS_FROM_REG(nr, data->in_max[nr])); } static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, @@ -656,8 +662,8 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr, { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMPEXT_FROM_REG(data->temp[nr], - data->temp_ext[nr])); + return sprintf(buf, "%d\n", TEMPEXT_FROM_REG(data->temp[nr], + data->temp_ext[nr])); } static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, @@ -665,7 +671,7 @@ static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr]) ); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr])); } static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, @@ -688,7 +694,7 @@ static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr]) ); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr])); } static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, @@ -697,7 +703,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->temp_max[nr] = TEMP_TO_REG(val); @@ -726,7 +732,7 @@ static ssize_t show_pwm_auto_channels(struct device *dev, { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", ZONE_FROM_REG(data->autofan[nr].config)); + return sprintf(buf, "%d\n", ZONE_FROM_REG(data->autofan[nr].config)); } static ssize_t set_pwm_auto_channels(struct device *dev, @@ -735,11 +741,11 @@ static ssize_t set_pwm_auto_channels(struct device *dev, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->autofan[nr].config = (data->autofan[nr].config & (~0xe0)) - | ZONE_TO_REG(val) ; + | ZONE_TO_REG(val); lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr), data->autofan[nr].config); mutex_unlock(&data->update_lock); @@ -751,7 +757,7 @@ static ssize_t show_pwm_auto_pwm_min(struct device *dev, { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", PWM_FROM_REG(data->autofan[nr].min_pwm)); + return sprintf(buf, "%d\n", PWM_FROM_REG(data->autofan[nr].min_pwm)); } static ssize_t set_pwm_auto_pwm_min(struct device *dev, @@ -775,7 +781,7 @@ static ssize_t show_pwm_auto_pwm_minctl(struct device *dev, { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", data->autofan[nr].min_off); + return sprintf(buf, "%d\n", data->autofan[nr].min_off); } static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, @@ -792,8 +798,7 @@ static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, | data->syncpwm3 | (data->autofan[0].min_off ? 0x20 : 0) | (data->autofan[1].min_off ? 0x40 : 0) - | (data->autofan[2].min_off ? 0x80 : 0) - ); + | (data->autofan[2].min_off ? 0x80 : 0)); mutex_unlock(&data->update_lock); return count; } @@ -803,7 +808,7 @@ static ssize_t show_pwm_auto_pwm_freq(struct device *dev, { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", FREQ_FROM_REG(data->autofan[nr].freq)); + return sprintf(buf, "%d\n", FREQ_FROM_REG(data->autofan[nr].freq)); } static ssize_t set_pwm_auto_pwm_freq(struct device *dev, @@ -818,8 +823,7 @@ static ssize_t set_pwm_auto_pwm_freq(struct device *dev, data->autofan[nr].freq = FREQ_TO_REG(val); lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), (data->zone[nr].range << 4) - | data->autofan[nr].freq - ); + | data->autofan[nr].freq); mutex_unlock(&data->update_lock); return count; } @@ -849,7 +853,7 @@ static ssize_t show_temp_auto_temp_off(struct device *dev, { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) - + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->zone[nr].limit) - HYST_FROM_REG(data->zone[nr].hyst)); } @@ -866,15 +870,13 @@ static ssize_t set_temp_auto_temp_off(struct device *dev, min = TEMP_FROM_REG(data->zone[nr].limit); data->zone[nr].off_desired = TEMP_TO_REG(val); data->zone[nr].hyst = HYST_TO_REG(min - val); - if ( nr == 0 || nr == 1 ) { + if (nr == 0 || nr == 1) { lm85_write_value(client, LM85_REG_AFAN_HYST1, (data->zone[0].hyst << 4) - | data->zone[1].hyst - ); + | data->zone[1].hyst); } else { lm85_write_value(client, LM85_REG_AFAN_HYST2, - (data->zone[2].hyst << 4) - ); + (data->zone[2].hyst << 4)); } mutex_unlock(&data->update_lock); return count; @@ -885,7 +887,7 @@ static ssize_t show_temp_auto_temp_min(struct device *dev, { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) ); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->zone[nr].limit)); } static ssize_t set_temp_auto_temp_min(struct device *dev, @@ -913,15 +915,13 @@ static ssize_t set_temp_auto_temp_min(struct device *dev, data->zone[nr].hyst = HYST_TO_REG(TEMP_FROM_REG( data->zone[nr].limit) - TEMP_FROM_REG( data->zone[nr].off_desired)); - if ( nr == 0 || nr == 1 ) { + if (nr == 0 || nr == 1) { lm85_write_value(client, LM85_REG_AFAN_HYST1, (data->zone[0].hyst << 4) - | data->zone[1].hyst - ); + | data->zone[1].hyst); } else { lm85_write_value(client, LM85_REG_AFAN_HYST2, - (data->zone[2].hyst << 4) - ); + (data->zone[2].hyst << 4)); } mutex_unlock(&data->update_lock); return count; @@ -932,7 +932,7 @@ static ssize_t show_temp_auto_temp_max(struct device *dev, { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) + + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->zone[nr].limit) + RANGE_FROM_REG(data->zone[nr].range)); } @@ -962,11 +962,11 @@ static ssize_t show_temp_auto_temp_crit(struct device *dev, { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].critical)); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->zone[nr].critical)); } static ssize_t set_temp_auto_temp_crit(struct device *dev, - struct device_attribute *attr,const char *buf, size_t count) + struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); @@ -1130,7 +1130,7 @@ static const struct attribute_group lm85_group_in567 = { static int lm85_detect(struct i2c_adapter *adapter, int address, int kind) { - int company, verstep ; + int company, verstep; struct i2c_client *new_client = NULL; struct lm85_data *data; int err = 0; @@ -1139,8 +1139,8 @@ static int lm85_detect(struct i2c_adapter *adapter, int address, if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { /* We need to be able to do byte I/O */ - goto ERROR0 ; - }; + goto ERROR0; + } /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. @@ -1171,82 +1171,81 @@ static int lm85_detect(struct i2c_adapter *adapter, int address, /* If auto-detecting, Determine the chip type. */ if (kind <= 0) { dev_dbg(&adapter->dev, "Autodetecting device at %d,0x%02x ...\n", - i2c_adapter_id(adapter), address ); - if( company == LM85_COMPANY_NATIONAL - && verstep == LM85_VERSTEP_LM85C ) { - kind = lm85c ; - } else if( company == LM85_COMPANY_NATIONAL - && verstep == LM85_VERSTEP_LM85B ) { - kind = lm85b ; - } else if( company == LM85_COMPANY_NATIONAL - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC ) { + i2c_adapter_id(adapter), address); + if (company == LM85_COMPANY_NATIONAL + && verstep == LM85_VERSTEP_LM85C) { + kind = lm85c; + } else if (company == LM85_COMPANY_NATIONAL + && verstep == LM85_VERSTEP_LM85B) { + kind = lm85b; + } else if (company == LM85_COMPANY_NATIONAL + && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { dev_err(&adapter->dev, "Unrecognized version/stepping 0x%02x" " Defaulting to LM85.\n", verstep); - kind = any_chip ; - } else if( company == LM85_COMPANY_ANALOG_DEV - && verstep == LM85_VERSTEP_ADM1027 ) { - kind = adm1027 ; - } else if( company == LM85_COMPANY_ANALOG_DEV + kind = any_chip; + } else if (company == LM85_COMPANY_ANALOG_DEV + && verstep == LM85_VERSTEP_ADM1027) { + kind = adm1027; + } else if (company == LM85_COMPANY_ANALOG_DEV && (verstep == LM85_VERSTEP_ADT7463 - || verstep == LM85_VERSTEP_ADT7463C) ) { - kind = adt7463 ; - } else if( company == LM85_COMPANY_ANALOG_DEV - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC ) { + || verstep == LM85_VERSTEP_ADT7463C)) { + kind = adt7463; + } else if (company == LM85_COMPANY_ANALOG_DEV + && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { dev_err(&adapter->dev, "Unrecognized version/stepping 0x%02x" - " Defaulting to Generic LM85.\n", verstep ); - kind = any_chip ; - } else if( company == LM85_COMPANY_SMSC + " Defaulting to Generic LM85.\n", verstep); + kind = any_chip; + } else if (company == LM85_COMPANY_SMSC && (verstep == LM85_VERSTEP_EMC6D100_A0 - || verstep == LM85_VERSTEP_EMC6D100_A1) ) { + || verstep == LM85_VERSTEP_EMC6D100_A1)) { /* Unfortunately, we can't tell a '100 from a '101 * from the registers. Since a '101 is a '100 * in a package with fewer pins and therefore no * 3.3V, 1.5V or 1.8V inputs, perhaps if those * inputs read 0, then it's a '101. */ - kind = emc6d100 ; - } else if( company == LM85_COMPANY_SMSC + kind = emc6d100; + } else if (company == LM85_COMPANY_SMSC && verstep == LM85_VERSTEP_EMC6D102) { - kind = emc6d102 ; - } else if( company == LM85_COMPANY_SMSC + kind = emc6d102; + } else if (company == LM85_COMPANY_SMSC && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { dev_err(&adapter->dev, "lm85: Detected SMSC chip\n"); dev_err(&adapter->dev, "lm85: Unrecognized version/stepping 0x%02x" - " Defaulting to Generic LM85.\n", verstep ); - kind = any_chip ; - } else if( kind == any_chip + " Defaulting to Generic LM85.\n", verstep); + kind = any_chip; + } else if (kind == any_chip && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { dev_err(&adapter->dev, "Generic LM85 Version 6 detected\n"); /* Leave kind as "any_chip" */ } else { dev_dbg(&adapter->dev, "Autodetection failed\n"); - /* Not an LM85 ... */ - if( kind == any_chip ) { /* User used force=x,y */ + /* Not an LM85... */ + if (kind == any_chip) { /* User used force=x,y */ dev_err(&adapter->dev, "Generic LM85 Version 6 not" " found at %d,0x%02x. Try force_lm85c.\n", - i2c_adapter_id(adapter), address ); + i2c_adapter_id(adapter), address); } - err = 0 ; + err = 0; goto ERROR1; } } /* Fill in the chip specific driver values */ - if ( kind == any_chip ) { + if (kind == any_chip) type_name = "lm85"; - } else if ( kind == lm85b ) { + else if (kind == lm85b) type_name = "lm85b"; - } else if ( kind == lm85c ) { + else if (kind == lm85c) type_name = "lm85c"; - } else if ( kind == adm1027 ) { + else if (kind == adm1027) type_name = "adm1027"; - } else if ( kind == adt7463 ) { + else if (kind == adt7463) type_name = "adt7463"; - } else if ( kind == emc6d100){ + else if (kind == emc6d100) type_name = "emc6d100"; - } else if ( kind == emc6d102 ) { + else if (kind == emc6d102) type_name = "emc6d102"; - } strlcpy(new_client->name, type_name, I2C_NAME_SIZE); /* Fill in the remaining client fields */ @@ -1291,16 +1290,16 @@ static int lm85_detect(struct i2c_adapter *adapter, int address, return 0; /* Error out and cleanup code */ - ERROR3: + ERROR3: sysfs_remove_group(&new_client->dev.kobj, &lm85_group); sysfs_remove_group(&new_client->dev.kobj, &lm85_group_in4); if (kind == emc6d100) sysfs_remove_group(&new_client->dev.kobj, &lm85_group_in567); - ERROR2: + ERROR2: i2c_detach_client(new_client); - ERROR1: + ERROR1: kfree(data); - ERROR0: + ERROR0: return err; } @@ -1323,58 +1322,60 @@ static int lm85_read_value(struct i2c_client *client, u8 reg) int res; /* What size location is it? */ - switch( reg ) { - case LM85_REG_FAN(0) : /* Read WORD data */ - case LM85_REG_FAN(1) : - case LM85_REG_FAN(2) : - case LM85_REG_FAN(3) : - case LM85_REG_FAN_MIN(0) : - case LM85_REG_FAN_MIN(1) : - case LM85_REG_FAN_MIN(2) : - case LM85_REG_FAN_MIN(3) : - case LM85_REG_ALARM1 : /* Read both bytes at once */ - res = i2c_smbus_read_byte_data(client, reg) & 0xff ; - res |= i2c_smbus_read_byte_data(client, reg+1) << 8 ; - break ; - case ADT7463_REG_TMIN_CTL1 : /* Read WORD MSB, LSB */ - res = i2c_smbus_read_byte_data(client, reg) << 8 ; - res |= i2c_smbus_read_byte_data(client, reg+1) & 0xff ; - break ; + switch (reg) { + case LM85_REG_FAN(0): /* Read WORD data */ + case LM85_REG_FAN(1): + case LM85_REG_FAN(2): + case LM85_REG_FAN(3): + case LM85_REG_FAN_MIN(0): + case LM85_REG_FAN_MIN(1): + case LM85_REG_FAN_MIN(2): + case LM85_REG_FAN_MIN(3): + case LM85_REG_ALARM1: /* Read both bytes at once */ + res = i2c_smbus_read_byte_data(client, reg) & 0xff; + res |= i2c_smbus_read_byte_data(client, reg + 1) << 8; + break; + case ADT7463_REG_TMIN_CTL1: /* Read WORD MSB, LSB */ + res = i2c_smbus_read_byte_data(client, reg) << 8; + res |= i2c_smbus_read_byte_data(client, reg + 1) & 0xff; + break; default: /* Read BYTE data */ res = i2c_smbus_read_byte_data(client, reg); - break ; + break; } - return res ; + return res; } static int lm85_write_value(struct i2c_client *client, u8 reg, int value) { - int res ; - - switch( reg ) { - case LM85_REG_FAN(0) : /* Write WORD data */ - case LM85_REG_FAN(1) : - case LM85_REG_FAN(2) : - case LM85_REG_FAN(3) : - case LM85_REG_FAN_MIN(0) : - case LM85_REG_FAN_MIN(1) : - case LM85_REG_FAN_MIN(2) : - case LM85_REG_FAN_MIN(3) : + int res; + + switch (reg) { + case LM85_REG_FAN(0): /* Write WORD data */ + case LM85_REG_FAN(1): + case LM85_REG_FAN(2): + case LM85_REG_FAN(3): + case LM85_REG_FAN_MIN(0): + case LM85_REG_FAN_MIN(1): + case LM85_REG_FAN_MIN(2): + case LM85_REG_FAN_MIN(3): /* NOTE: ALARM is read only, so not included here */ - res = i2c_smbus_write_byte_data(client, reg, value & 0xff) ; - res |= i2c_smbus_write_byte_data(client, reg+1, (value>>8) & 0xff) ; - break ; - case ADT7463_REG_TMIN_CTL1 : /* Write WORD MSB, LSB */ - res = i2c_smbus_write_byte_data(client, reg, (value>>8) & 0xff); - res |= i2c_smbus_write_byte_data(client, reg+1, value & 0xff) ; - break ; + res = i2c_smbus_write_byte_data(client, reg, value & 0xff); + res |= i2c_smbus_write_byte_data(client, reg + 1, + (value >> 8) & 0xff); + break; + case ADT7463_REG_TMIN_CTL1: /* Write WORD MSB, LSB */ + res = i2c_smbus_write_byte_data(client, reg, + (value >> 8) & 0xff); + res |= i2c_smbus_write_byte_data(client, reg + 1, value & 0xff); + break; default: /* Write BYTE data */ res = i2c_smbus_write_byte_data(client, reg, value); - break ; + break; } - return res ; + return res; } static void lm85_init_client(struct i2c_client *client) @@ -1387,21 +1388,21 @@ static void lm85_init_client(struct i2c_client *client) /* Warn if part was not "READY" */ value = lm85_read_value(client, LM85_REG_CONFIG); dev_dbg(&client->dev, "LM85_REG_CONFIG is: 0x%02x\n", value); - if( value & 0x02 ) { + if (value & 0x02) { dev_err(&client->dev, "Client (%d,0x%02x) config is locked.\n", - i2c_adapter_id(client->adapter), client->addr ); - }; - if( ! (value & 0x04) ) { + i2c_adapter_id(client->adapter), client->addr); + } + if (!(value & 0x04)) { dev_err(&client->dev, "Client (%d,0x%02x) is not ready.\n", - i2c_adapter_id(client->adapter), client->addr ); - }; - if( value & 0x10 - && ( data->type == adm1027 - || data->type == adt7463 ) ) { + i2c_adapter_id(client->adapter), client->addr); + } + if (value & 0x10 + && (data->type == adm1027 + || data->type == adt7463)) { dev_err(&client->dev, "Client (%d,0x%02x) VxI mode is set. " "Please report this to the lm85 maintainer.\n", - i2c_adapter_id(client->adapter), client->addr ); - }; + i2c_adapter_id(client->adapter), client->addr); + } /* WE INTENTIONALLY make no changes to the limits, * offsets, pwms, fans and zones. If they were @@ -1414,7 +1415,7 @@ static void lm85_init_client(struct i2c_client *client) /* Start monitoring */ value = lm85_read_value(client, LM85_REG_CONFIG); /* Try to clear LOCK, Set START, save everything else */ - value = (value & ~ 0x02) | 0x01 ; + value = (value & ~0x02) | 0x01; dev_dbg(&client->dev, "Setting CONFIG to: 0x%02x\n", value); lm85_write_value(client, LM85_REG_CONFIG, value); } @@ -1427,28 +1428,30 @@ static struct lm85_data *lm85_update_device(struct device *dev) mutex_lock(&data->update_lock); - if ( !data->valid || - time_after(jiffies, data->last_reading + LM85_DATA_INTERVAL) ) { + if (!data->valid || + time_after(jiffies, data->last_reading + LM85_DATA_INTERVAL)) { /* Things that change quickly */ dev_dbg(&client->dev, "Reading sensor values\n"); - + /* Have to read extended bits first to "freeze" the * more significant bits that are read later. * There are 2 additional resolution bits per channel and we * have room for 4, so we shift them to the left. */ - if ( (data->type == adm1027) || (data->type == adt7463) ) { + if (data->type == adm1027 || data->type == adt7463) { int ext1 = lm85_read_value(client, ADM1027_REG_EXTEND_ADC1); int ext2 = lm85_read_value(client, ADM1027_REG_EXTEND_ADC2); int val = (ext1 << 8) + ext2; - for(i = 0; i <= 4; i++) - data->in_ext[i] = ((val>>(i * 2))&0x03) << 2; + for (i = 0; i <= 4; i++) + data->in_ext[i] = + ((val >> (i * 2)) & 0x03) << 2; - for(i = 0; i <= 2; i++) - data->temp_ext[i] = (val>>((i + 4) * 2))&0x0c; + for (i = 0; i <= 2; i++) + data->temp_ext[i] = + (val >> ((i + 4) * 2)) & 0x0c; } data->vid = lm85_read_value(client, LM85_REG_VID); @@ -1480,21 +1483,21 @@ static struct lm85_data *lm85_update_device(struct device *dev) data->alarms = lm85_read_value(client, LM85_REG_ALARM1); - if ( data->type == adt7463 ) { - if( data->therm_total < ULONG_MAX - 256 ) { + if (data->type == adt7463) { + if (data->therm_total < ULONG_MAX - 256) { data->therm_total += - lm85_read_value(client, ADT7463_REG_THERM ); + lm85_read_value(client, ADT7463_REG_THERM); } - } else if ( data->type == emc6d100 ) { + } else if (data->type == emc6d100) { /* Three more voltage sensors */ for (i = 5; i <= 7; ++i) { - data->in[i] = - lm85_read_value(client, EMC6D100_REG_IN(i)); + data->in[i] = lm85_read_value(client, + EMC6D100_REG_IN(i)); } /* More alarm bits */ - data->alarms |= - lm85_read_value(client, EMC6D100_REG_ALARM3) << 16; - } else if (data->type == emc6d102 ) { + data->alarms |= lm85_read_value(client, + EMC6D100_REG_ALARM3) << 16; + } else if (data->type == emc6d102) { /* Have to read LSB bits after the MSB ones because the reading of the MSB bits has frozen the LSBs (backward from the ADM1027). @@ -1518,11 +1521,11 @@ static struct lm85_data *lm85_update_device(struct device *dev) data->temp_ext[2] = (ext1 >> 4) & 0x0f; } - data->last_reading = jiffies ; - }; /* last_reading */ + data->last_reading = jiffies; + } /* last_reading */ - if ( !data->valid || - time_after(jiffies, data->last_config + LM85_CONFIG_INTERVAL) ) { + if (!data->valid || + time_after(jiffies, data->last_config + LM85_CONFIG_INTERVAL)) { /* Things that don't change often */ dev_dbg(&client->dev, "Reading config values\n"); @@ -1540,12 +1543,12 @@ static struct lm85_data *lm85_update_device(struct device *dev) LM85_REG_IN_MAX(4)); } - if ( data->type == emc6d100 ) { + if (data->type == emc6d100) { for (i = 5; i <= 7; ++i) { - data->in_min[i] = - lm85_read_value(client, EMC6D100_REG_IN_MIN(i)); - data->in_max[i] = - lm85_read_value(client, EMC6D100_REG_IN_MAX(i)); + data->in_min[i] = lm85_read_value(client, + EMC6D100_REG_IN_MIN(i)); + data->in_max[i] = lm85_read_value(client, + EMC6D100_REG_IN_MAX(i)); } } @@ -1562,12 +1565,12 @@ static struct lm85_data *lm85_update_device(struct device *dev) } for (i = 0; i <= 2; ++i) { - int val ; + int val; data->autofan[i].config = lm85_read_value(client, LM85_REG_AFAN_CONFIG(i)); val = lm85_read_value(client, LM85_REG_AFAN_RANGE(i)); - data->autofan[i].freq = val & 0x07 ; - data->zone[i].range = (val >> 4) & 0x0f ; + data->autofan[i].freq = val & 0x07; + data->zone[i].range = (val >> 4) & 0x0f; data->autofan[i].min_pwm = lm85_read_value(client, LM85_REG_AFAN_MINPWM(i)); data->zone[i].limit = @@ -1577,50 +1580,50 @@ static struct lm85_data *lm85_update_device(struct device *dev) } i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1); - data->smooth[0] = i & 0x0f ; - data->syncpwm3 = i & 0x10 ; /* Save PWM3 config */ - data->autofan[0].min_off = (i & 0x20) != 0 ; - data->autofan[1].min_off = (i & 0x40) != 0 ; - data->autofan[2].min_off = (i & 0x80) != 0 ; + data->smooth[0] = i & 0x0f; + data->syncpwm3 = i & 0x10; /* Save PWM3 config */ + data->autofan[0].min_off = (i & 0x20) != 0; + data->autofan[1].min_off = (i & 0x40) != 0; + data->autofan[2].min_off = (i & 0x80) != 0; i = lm85_read_value(client, LM85_REG_AFAN_SPIKE2); - data->smooth[1] = (i>>4) & 0x0f ; - data->smooth[2] = i & 0x0f ; + data->smooth[1] = (i >> 4) & 0x0f; + data->smooth[2] = i & 0x0f; i = lm85_read_value(client, LM85_REG_AFAN_HYST1); - data->zone[0].hyst = (i>>4) & 0x0f ; - data->zone[1].hyst = i & 0x0f ; + data->zone[0].hyst = (i >> 4) & 0x0f; + data->zone[1].hyst = i & 0x0f; i = lm85_read_value(client, LM85_REG_AFAN_HYST2); - data->zone[2].hyst = (i>>4) & 0x0f ; + data->zone[2].hyst = (i >> 4) & 0x0f; - if ( (data->type == lm85b) || (data->type == lm85c) ) { + if (data->type == lm85b || data->type == lm85c) { data->tach_mode = lm85_read_value(client, - LM85_REG_TACH_MODE ); + LM85_REG_TACH_MODE); data->spinup_ctl = lm85_read_value(client, - LM85_REG_SPINUP_CTL ); - } else if ( (data->type == adt7463) || (data->type == adm1027) ) { - if ( data->type == adt7463 ) { + LM85_REG_SPINUP_CTL); + } else if (data->type == adt7463 || data->type == adm1027) { + if (data->type == adt7463) { for (i = 0; i <= 2; ++i) { data->oppoint[i] = lm85_read_value(client, - ADT7463_REG_OPPOINT(i) ); + ADT7463_REG_OPPOINT(i)); } data->tmin_ctl = lm85_read_value(client, - ADT7463_REG_TMIN_CTL1 ); + ADT7463_REG_TMIN_CTL1); data->therm_limit = lm85_read_value(client, - ADT7463_REG_THERM_LIMIT ); + ADT7463_REG_THERM_LIMIT); } for (i = 0; i <= 2; ++i) { - data->temp_offset[i] = lm85_read_value(client, - ADM1027_REG_TEMP_OFFSET(i) ); + data->temp_offset[i] = lm85_read_value(client, + ADM1027_REG_TEMP_OFFSET(i)); } data->tach_mode = lm85_read_value(client, - ADM1027_REG_CONFIG3 ); + ADM1027_REG_CONFIG3); data->fan_ppr = lm85_read_value(client, - ADM1027_REG_FAN_PPR ); + ADM1027_REG_FAN_PPR); } - + data->last_config = jiffies; - }; /* last_config */ + } /* last_config */ data->valid = 1; @@ -1635,7 +1638,7 @@ static int __init sm_lm85_init(void) return i2c_add_driver(&lm85_driver); } -static void __exit sm_lm85_exit(void) +static void __exit sm_lm85_exit(void) { i2c_del_driver(&lm85_driver); } @@ -1645,7 +1648,9 @@ static void __exit sm_lm85_exit(void) * post 2.7.0 CVS changes. */ MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Philip Pokorny , Margit Schubert-While , Justin Thiessen , " + "Margit Schubert-While , " + "Justin Thiessen Date: Thu, 1 May 2008 08:47:33 +0200 Subject: hwmon: (lm85) Drop dead code Drop a lot of useless register defines, conversion macros, data structure members and update code. All these register values were read from the device but nothing is done out of them, so this is all dead code in practice. Signed-off-by: Jean Delvare Acked-by: Juerg Haefliger Signed-off-by: Mark M. Hoffman --- drivers/hwmon/lm85.c | 82 ++-------------------------------------------------- 1 file changed, 2 insertions(+), 80 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 0c0fede8dde..0d31435b333 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -56,16 +56,9 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102); #define LM85_REG_PWM(nr) (0x30 + (nr)) -#define ADT7463_REG_OPPOINT(nr) (0x33 + (nr)) - -#define ADT7463_REG_TMIN_CTL1 0x36 -#define ADT7463_REG_TMIN_CTL2 0x37 - -#define LM85_REG_DEVICE 0x3d #define LM85_REG_COMPANY 0x3e #define LM85_REG_VERSTEP 0x3f /* These are the recognized values for the above regs */ -#define LM85_DEVICE_ADX 0x27 #define LM85_COMPANY_NATIONAL 0x01 #define LM85_COMPANY_ANALOG_DEV 0x41 #define LM85_COMPANY_SMSC 0x5c @@ -91,27 +84,14 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102); #define LM85_REG_AFAN_CONFIG(nr) (0x5c + (nr)) #define LM85_REG_AFAN_RANGE(nr) (0x5f + (nr)) #define LM85_REG_AFAN_SPIKE1 0x62 -#define LM85_REG_AFAN_SPIKE2 0x63 #define LM85_REG_AFAN_MINPWM(nr) (0x64 + (nr)) #define LM85_REG_AFAN_LIMIT(nr) (0x67 + (nr)) #define LM85_REG_AFAN_CRITICAL(nr) (0x6a + (nr)) #define LM85_REG_AFAN_HYST1 0x6d #define LM85_REG_AFAN_HYST2 0x6e -#define LM85_REG_TACH_MODE 0x74 -#define LM85_REG_SPINUP_CTL 0x75 - -#define ADM1027_REG_TEMP_OFFSET(nr) (0x70 + (nr)) -#define ADM1027_REG_CONFIG2 0x73 -#define ADM1027_REG_INTMASK1 0x74 -#define ADM1027_REG_INTMASK2 0x75 #define ADM1027_REG_EXTEND_ADC1 0x76 #define ADM1027_REG_EXTEND_ADC2 0x77 -#define ADM1027_REG_CONFIG3 0x78 -#define ADM1027_REG_FAN_PPR 0x7b - -#define ADT7463_REG_THERM 0x79 -#define ADT7463_REG_THERM_LIMIT 0x7A #define EMC6D100_REG_ALARM3 0x7d /* IN5, IN6 and IN7 */ @@ -263,13 +243,6 @@ static int ZONE_TO_REG(int zone) #define HYST_TO_REG(val) SENSORS_LIMIT(((val) + 500) / 1000, 0, 15) #define HYST_FROM_REG(val) ((val) * 1000) -#define OFFSET_TO_REG(val) SENSORS_LIMIT((val) / 25, -127, 127) -#define OFFSET_FROM_REG(val) ((val) * 25) - -#define PPR_MASK(fan) (0x03 << ((fan) * 2)) -#define PPR_TO_REG(val, fan) (SENSORS_LIMIT((val) - 1, 0, 3) << ((fan) * 2)) -#define PPR_FROM_REG(val, fan) ((((val) >> ((fan) * 2)) & 0x03) + 1) - /* Chip sampling rates * * Some sensors are not updated more frequently than once per second @@ -330,23 +303,15 @@ struct lm85_data { s8 temp[3]; /* Register value */ s8 temp_min[3]; /* Register value */ s8 temp_max[3]; /* Register value */ - s8 temp_offset[3]; /* Register value */ u16 fan[4]; /* Register value */ u16 fan_min[4]; /* Register value */ u8 pwm[3]; /* Register value */ - u8 spinup_ctl; /* Register encoding, combined */ - u8 tach_mode; /* Register encoding, combined */ u8 temp_ext[3]; /* Decoded values */ u8 in_ext[8]; /* Decoded values */ - u8 fan_ppr; /* Register value */ - u8 smooth[3]; /* Register encoding */ + u8 smooth[1]; /* Register encoding */ u8 vid; /* Register value */ u8 vrm; /* VRM version */ u8 syncpwm3; /* Saved PWM3 for TACH 2,3,4 config */ - u8 oppoint[3]; /* Register value */ - u16 tmin_ctl; /* Register value */ - unsigned long therm_total; /* Cummulative therm count */ - u8 therm_limit; /* Register value */ u32 alarms; /* Register encoding, combined */ struct lm85_autofan autofan[3]; struct lm85_zone zone[3]; @@ -1335,10 +1300,6 @@ static int lm85_read_value(struct i2c_client *client, u8 reg) res = i2c_smbus_read_byte_data(client, reg) & 0xff; res |= i2c_smbus_read_byte_data(client, reg + 1) << 8; break; - case ADT7463_REG_TMIN_CTL1: /* Read WORD MSB, LSB */ - res = i2c_smbus_read_byte_data(client, reg) << 8; - res |= i2c_smbus_read_byte_data(client, reg + 1) & 0xff; - break; default: /* Read BYTE data */ res = i2c_smbus_read_byte_data(client, reg); break; @@ -1365,11 +1326,6 @@ static int lm85_write_value(struct i2c_client *client, u8 reg, int value) res |= i2c_smbus_write_byte_data(client, reg + 1, (value >> 8) & 0xff); break; - case ADT7463_REG_TMIN_CTL1: /* Write WORD MSB, LSB */ - res = i2c_smbus_write_byte_data(client, reg, - (value >> 8) & 0xff); - res |= i2c_smbus_write_byte_data(client, reg + 1, value & 0xff); - break; default: /* Write BYTE data */ res = i2c_smbus_write_byte_data(client, reg, value); break; @@ -1483,12 +1439,7 @@ static struct lm85_data *lm85_update_device(struct device *dev) data->alarms = lm85_read_value(client, LM85_REG_ALARM1); - if (data->type == adt7463) { - if (data->therm_total < ULONG_MAX - 256) { - data->therm_total += - lm85_read_value(client, ADT7463_REG_THERM); - } - } else if (data->type == emc6d100) { + if (data->type == emc6d100) { /* Three more voltage sensors */ for (i = 5; i <= 7; ++i) { data->in[i] = lm85_read_value(client, @@ -1585,9 +1536,6 @@ static struct lm85_data *lm85_update_device(struct device *dev) data->autofan[0].min_off = (i & 0x20) != 0; data->autofan[1].min_off = (i & 0x40) != 0; data->autofan[2].min_off = (i & 0x80) != 0; - i = lm85_read_value(client, LM85_REG_AFAN_SPIKE2); - data->smooth[1] = (i >> 4) & 0x0f; - data->smooth[2] = i & 0x0f; i = lm85_read_value(client, LM85_REG_AFAN_HYST1); data->zone[0].hyst = (i >> 4) & 0x0f; @@ -1596,32 +1544,6 @@ static struct lm85_data *lm85_update_device(struct device *dev) i = lm85_read_value(client, LM85_REG_AFAN_HYST2); data->zone[2].hyst = (i >> 4) & 0x0f; - if (data->type == lm85b || data->type == lm85c) { - data->tach_mode = lm85_read_value(client, - LM85_REG_TACH_MODE); - data->spinup_ctl = lm85_read_value(client, - LM85_REG_SPINUP_CTL); - } else if (data->type == adt7463 || data->type == adm1027) { - if (data->type == adt7463) { - for (i = 0; i <= 2; ++i) { - data->oppoint[i] = lm85_read_value(client, - ADT7463_REG_OPPOINT(i)); - } - data->tmin_ctl = lm85_read_value(client, - ADT7463_REG_TMIN_CTL1); - data->therm_limit = lm85_read_value(client, - ADT7463_REG_THERM_LIMIT); - } - for (i = 0; i <= 2; ++i) { - data->temp_offset[i] = lm85_read_value(client, - ADM1027_REG_TEMP_OFFSET(i)); - } - data->tach_mode = lm85_read_value(client, - ADM1027_REG_CONFIG3); - data->fan_ppr = lm85_read_value(client, - ADM1027_REG_FAN_PPR); - } - data->last_config = jiffies; } /* last_config */ -- cgit v1.2.3 From 7133e56f29030b13601d3399e20050053e560860 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 12 Apr 2008 19:56:35 +0200 Subject: hwmon: (lm85) Don't write back cached values In set_pwm_auto_pwm_minctl, we write cached register bits back to the chip. This is a bad idea as we have no guarantee that the cache is up-to-date. Better read a fresh register value from the chip, it's safer and in fact it is also more simple. Signed-off-by: Jean Delvare Acked-by: Juerg Haefliger Signed-off-by: Mark M. Hoffman --- drivers/hwmon/lm85.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 0d31435b333..645b98c187c 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -308,10 +308,8 @@ struct lm85_data { u8 pwm[3]; /* Register value */ u8 temp_ext[3]; /* Decoded values */ u8 in_ext[8]; /* Decoded values */ - u8 smooth[1]; /* Register encoding */ u8 vid; /* Register value */ u8 vrm; /* VRM version */ - u8 syncpwm3; /* Saved PWM3 for TACH 2,3,4 config */ u32 alarms; /* Register encoding, combined */ struct lm85_autofan autofan[3]; struct lm85_zone zone[3]; @@ -756,14 +754,15 @@ static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); + u8 tmp; mutex_lock(&data->update_lock); data->autofan[nr].min_off = val; - lm85_write_value(client, LM85_REG_AFAN_SPIKE1, data->smooth[0] - | data->syncpwm3 - | (data->autofan[0].min_off ? 0x20 : 0) - | (data->autofan[1].min_off ? 0x40 : 0) - | (data->autofan[2].min_off ? 0x80 : 0)); + tmp = lm85_read_value(client, LM85_REG_AFAN_SPIKE1); + tmp &= ~(0x20 << nr); + if (data->autofan[nr].min_off) + tmp |= 0x20 << nr; + lm85_write_value(client, LM85_REG_AFAN_SPIKE1, tmp); mutex_unlock(&data->update_lock); return count; } @@ -1531,8 +1530,6 @@ static struct lm85_data *lm85_update_device(struct device *dev) } i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1); - data->smooth[0] = i & 0x0f; - data->syncpwm3 = i & 0x10; /* Save PWM3 config */ data->autofan[0].min_off = (i & 0x20) != 0; data->autofan[1].min_off = (i & 0x40) != 0; data->autofan[2].min_off = (i & 0x80) != 0; -- cgit v1.2.3 From e89e22b23bceb3fbbcfb931ad17a564b7c1eaa55 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 25 Jun 2008 08:47:35 -0400 Subject: hwmon: (lm85) Misc cleanups Misc cleanups to the lm85 hardware monitoring driver: * Mark constant arrays as const. * Remove useless masks. * Have lm85_write_value return void - nobody is checking the returned value anyway and in some cases it was plain wrong. * Remove useless initializations. * Rename new_client to client in lm85_detect. * Replace cascaded if/else with a switch/case in lm85_detect. * Group similar loops in lm85_update_device. * Remove legacy comments. Signed-off-by: Jean Delvare Acked-by: Juerg Haefliger Signed-off-by: Mark M. Hoffman --- drivers/hwmon/lm85.c | 151 +++++++++++++++++++++++---------------------------- 1 file changed, 67 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 645b98c187c..c7e10af0173 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -110,7 +110,7 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102); */ /* IN are scaled acording to built-in resistors */ -static int lm85_scaling[] = { /* .001 Volts */ +static const int lm85_scaling[] = { /* .001 Volts */ 2500, 2250, 3300, 5000, 12000, 3300, 1500, 1800 /*EMC6D100*/ }; @@ -164,7 +164,7 @@ static inline u16 FAN_TO_REG(unsigned long val) */ /* These are the zone temperature range encodings in .001 degree C */ -static int lm85_range_map[] = { +static const int lm85_range_map[] = { 2000, 2500, 3300, 4000, 5000, 6600, 8000, 10000, 13300, 16000, 20000, 26600, 32000, 40000, 53300, 80000 }; @@ -190,13 +190,8 @@ static int RANGE_TO_REG(int range) } #define RANGE_FROM_REG(val) lm85_range_map[(val) & 0x0f] -/* These are the Acoustic Enhancement, or Temperature smoothing encodings - * NOTE: The enable/disable bit is INCLUDED in these encodings as the - * MSB (bit 3, value 8). If the enable bit is 0, the encoded value - * is ignored, or set to 0. - */ /* These are the PWM frequency encodings */ -static int lm85_freq_map[] = { /* .1 Hz */ +static const int lm85_freq_map[] = { /* .1 Hz */ 100, 150, 230, 300, 380, 470, 620, 940 }; @@ -209,7 +204,7 @@ static int FREQ_TO_REG(int freq) for (i = 0; i < 7; ++i) if (freq <= lm85_freq_map[i]) break; - return i & 0x07; + return i; } #define FREQ_FROM_REG(val) lm85_freq_map[(val) & 0x07] @@ -225,8 +220,8 @@ static int FREQ_TO_REG(int freq) * -2 -- PWM responds to manual control */ -static int lm85_zone_map[] = { 1, 2, 3, -1, 0, 23, 123, -2 }; -#define ZONE_FROM_REG(val) lm85_zone_map[((val) >> 5) & 0x07] +static const int lm85_zone_map[] = { 1, 2, 3, -1, 0, 23, 123, -2 }; +#define ZONE_FROM_REG(val) lm85_zone_map[(val) >> 5] static int ZONE_TO_REG(int zone) { @@ -237,7 +232,7 @@ static int ZONE_TO_REG(int zone) break; if (i > 7) /* Not found. */ i = 3; /* Always 100% */ - return (i & 0x07) << 5; + return i << 5; } #define HYST_TO_REG(val) SENSORS_LIMIT(((val) + 500) / 1000, 0, 15) @@ -321,7 +316,7 @@ static int lm85_detect(struct i2c_adapter *adapter, int address, static int lm85_detach_client(struct i2c_client *client); static int lm85_read_value(struct i2c_client *client, u8 reg); -static int lm85_write_value(struct i2c_client *client, u8 reg, int value); +static void lm85_write_value(struct i2c_client *client, u8 reg, int value); static struct lm85_data *lm85_update_device(struct device *dev); static void lm85_init_client(struct i2c_client *client); @@ -1095,13 +1090,12 @@ static int lm85_detect(struct i2c_adapter *adapter, int address, int kind) { int company, verstep; - struct i2c_client *new_client = NULL; + struct i2c_client *client; struct lm85_data *data; int err = 0; - const char *type_name = ""; + const char *type_name; - if (!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) { + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { /* We need to be able to do byte I/O */ goto ERROR0; } @@ -1115,21 +1109,20 @@ static int lm85_detect(struct i2c_adapter *adapter, int address, goto ERROR0; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm85_driver; - new_client->flags = 0; + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &lm85_driver; /* Now, we do the remaining detection. */ - company = lm85_read_value(new_client, LM85_REG_COMPANY); - verstep = lm85_read_value(new_client, LM85_REG_VERSTEP); + company = lm85_read_value(client, LM85_REG_COMPANY); + verstep = lm85_read_value(client, LM85_REG_VERSTEP); dev_dbg(&adapter->dev, "Detecting device at %d,0x%02x with" " COMPANY: 0x%02x and VERSTEP: 0x%02x\n", - i2c_adapter_id(new_client->adapter), new_client->addr, + i2c_adapter_id(client->adapter), client->addr, company, verstep); /* If auto-detecting, Determine the chip type. */ @@ -1196,56 +1189,65 @@ static int lm85_detect(struct i2c_adapter *adapter, int address, } /* Fill in the chip specific driver values */ - if (kind == any_chip) - type_name = "lm85"; - else if (kind == lm85b) + switch (kind) { + case lm85b: type_name = "lm85b"; - else if (kind == lm85c) + break; + case lm85c: type_name = "lm85c"; - else if (kind == adm1027) + break; + case adm1027: type_name = "adm1027"; - else if (kind == adt7463) + break; + case adt7463: type_name = "adt7463"; - else if (kind == emc6d100) + break; + case emc6d100: type_name = "emc6d100"; - else if (kind == emc6d102) + break; + case emc6d102: type_name = "emc6d102"; - strlcpy(new_client->name, type_name, I2C_NAME_SIZE); + break; + default: + type_name = "lm85"; + } + strlcpy(client->name, type_name, I2C_NAME_SIZE); /* Fill in the remaining client fields */ data->type = kind; - data->valid = 0; mutex_init(&data->update_lock); /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) + err = i2c_attach_client(client); + if (err) goto ERROR1; /* Set the VRM version */ data->vrm = vid_which_vrm(); /* Initialize the LM85 chip */ - lm85_init_client(new_client); + lm85_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &lm85_group))) + err = sysfs_create_group(&client->dev.kobj, &lm85_group); + if (err) goto ERROR2; /* The ADT7463 has an optional VRM 10 mode where pin 21 is used as a sixth digital VID input rather than an analog input. */ - data->vid = lm85_read_value(new_client, LM85_REG_VID); + data->vid = lm85_read_value(client, LM85_REG_VID); if (!(kind == adt7463 && (data->vid & 0x80))) - if ((err = sysfs_create_group(&new_client->dev.kobj, + if ((err = sysfs_create_group(&client->dev.kobj, &lm85_group_in4))) goto ERROR3; /* The EMC6D100 has 3 additional voltage inputs */ if (kind == emc6d100) - if ((err = sysfs_create_group(&new_client->dev.kobj, + if ((err = sysfs_create_group(&client->dev.kobj, &lm85_group_in567))) goto ERROR3; - data->hwmon_dev = hwmon_device_register(&new_client->dev); + data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto ERROR3; @@ -1255,12 +1257,12 @@ static int lm85_detect(struct i2c_adapter *adapter, int address, /* Error out and cleanup code */ ERROR3: - sysfs_remove_group(&new_client->dev.kobj, &lm85_group); - sysfs_remove_group(&new_client->dev.kobj, &lm85_group_in4); + sysfs_remove_group(&client->dev.kobj, &lm85_group); + sysfs_remove_group(&client->dev.kobj, &lm85_group_in4); if (kind == emc6d100) - sysfs_remove_group(&new_client->dev.kobj, &lm85_group_in567); + sysfs_remove_group(&client->dev.kobj, &lm85_group_in567); ERROR2: - i2c_detach_client(new_client); + i2c_detach_client(client); ERROR1: kfree(data); ERROR0: @@ -1307,10 +1309,8 @@ static int lm85_read_value(struct i2c_client *client, u8 reg) return res; } -static int lm85_write_value(struct i2c_client *client, u8 reg, int value) +static void lm85_write_value(struct i2c_client *client, u8 reg, int value) { - int res; - switch (reg) { case LM85_REG_FAN(0): /* Write WORD data */ case LM85_REG_FAN(1): @@ -1321,16 +1321,13 @@ static int lm85_write_value(struct i2c_client *client, u8 reg, int value) case LM85_REG_FAN_MIN(2): case LM85_REG_FAN_MIN(3): /* NOTE: ALARM is read only, so not included here */ - res = i2c_smbus_write_byte_data(client, reg, value & 0xff); - res |= i2c_smbus_write_byte_data(client, reg + 1, - (value >> 8) & 0xff); + i2c_smbus_write_byte_data(client, reg, value & 0xff); + i2c_smbus_write_byte_data(client, reg + 1, value >> 8); break; default: /* Write BYTE data */ - res = i2c_smbus_write_byte_data(client, reg, value); + i2c_smbus_write_byte_data(client, reg, value); break; } - - return res; } static void lm85_init_client(struct i2c_client *client) @@ -1414,6 +1411,8 @@ static struct lm85_data *lm85_update_device(struct device *dev) for (i = 0; i <= 3; ++i) { data->in[i] = lm85_read_value(client, LM85_REG_IN(i)); + data->fan[i] = + lm85_read_value(client, LM85_REG_FAN(i)); } if (!(data->type == adt7463 && (data->vid & 0x80))) { @@ -1421,17 +1420,9 @@ static struct lm85_data *lm85_update_device(struct device *dev) LM85_REG_IN(4)); } - for (i = 0; i <= 3; ++i) { - data->fan[i] = - lm85_read_value(client, LM85_REG_FAN(i)); - } - for (i = 0; i <= 2; ++i) { data->temp[i] = lm85_read_value(client, LM85_REG_TEMP(i)); - } - - for (i = 0; i <= 2; ++i) { data->pwm[i] = lm85_read_value(client, LM85_REG_PWM(i)); } @@ -1462,13 +1453,13 @@ static struct lm85_data *lm85_update_device(struct device *dev) EMC6D102_REG_EXTEND_ADC4); data->in_ext[0] = ext3 & 0x0f; data->in_ext[1] = ext4 & 0x0f; - data->in_ext[2] = (ext4 >> 4) & 0x0f; - data->in_ext[3] = (ext3 >> 4) & 0x0f; - data->in_ext[4] = (ext2 >> 4) & 0x0f; + data->in_ext[2] = ext4 >> 4; + data->in_ext[3] = ext3 >> 4; + data->in_ext[4] = ext2 >> 4; data->temp_ext[0] = ext1 & 0x0f; data->temp_ext[1] = ext2 & 0x0f; - data->temp_ext[2] = (ext1 >> 4) & 0x0f; + data->temp_ext[2] = ext1 >> 4; } data->last_reading = jiffies; @@ -1484,6 +1475,8 @@ static struct lm85_data *lm85_update_device(struct device *dev) lm85_read_value(client, LM85_REG_IN_MIN(i)); data->in_max[i] = lm85_read_value(client, LM85_REG_IN_MAX(i)); + data->fan_min[i] = + lm85_read_value(client, LM85_REG_FAN_MIN(i)); } if (!(data->type == adt7463 && (data->vid & 0x80))) { @@ -1502,25 +1495,19 @@ static struct lm85_data *lm85_update_device(struct device *dev) } } - for (i = 0; i <= 3; ++i) { - data->fan_min[i] = - lm85_read_value(client, LM85_REG_FAN_MIN(i)); - } - for (i = 0; i <= 2; ++i) { + int val; + data->temp_min[i] = lm85_read_value(client, LM85_REG_TEMP_MIN(i)); data->temp_max[i] = lm85_read_value(client, LM85_REG_TEMP_MAX(i)); - } - for (i = 0; i <= 2; ++i) { - int val; data->autofan[i].config = lm85_read_value(client, LM85_REG_AFAN_CONFIG(i)); val = lm85_read_value(client, LM85_REG_AFAN_RANGE(i)); data->autofan[i].freq = val & 0x07; - data->zone[i].range = (val >> 4) & 0x0f; + data->zone[i].range = val >> 4; data->autofan[i].min_pwm = lm85_read_value(client, LM85_REG_AFAN_MINPWM(i)); data->zone[i].limit = @@ -1535,11 +1522,11 @@ static struct lm85_data *lm85_update_device(struct device *dev) data->autofan[2].min_off = (i & 0x80) != 0; i = lm85_read_value(client, LM85_REG_AFAN_HYST1); - data->zone[0].hyst = (i >> 4) & 0x0f; + data->zone[0].hyst = i >> 4; data->zone[1].hyst = i & 0x0f; i = lm85_read_value(client, LM85_REG_AFAN_HYST2); - data->zone[2].hyst = (i >> 4) & 0x0f; + data->zone[2].hyst = i >> 4; data->last_config = jiffies; } /* last_config */ @@ -1562,14 +1549,10 @@ static void __exit sm_lm85_exit(void) i2c_del_driver(&lm85_driver); } -/* Thanks to Richard Barrington for adding the LM85 to sensors-detect. - * Thanks to Margit Schubert-While for help with - * post 2.7.0 CVS changes. - */ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Philip Pokorny , " "Margit Schubert-While , " - "Justin Thiessen "); MODULE_DESCRIPTION("LM85-B, LM85-C driver"); module_init(sm_lm85_init); -- cgit v1.2.3 From 5f44759470f7248f74947a39cba339009d62052c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 25 Jun 2008 09:10:30 -0400 Subject: hwmon: (lm85) Simplify device initialization function Clean up and simplify the device initialization function: * Degrade error messages to warnings - what they really are. * Stop warning about VxI mode, we don't really care. * Drop comment about lack of limit initialization - that's the standard way, all hardware monitoring drivers do that. * Only read the configuration register once. * Only write back to the configuration register if needed. * Don't attempt to clear the lock bit, it locks itself to 1. * Move the function to before it's called, so that we no longer need to forware declare it. Signed-off-by: Jean Delvare Signed-off-by: Mark M. Hoffman --- drivers/hwmon/lm85.c | 61 ++++++++++++++++------------------------------------ 1 file changed, 18 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index c7e10af0173..12d446f54f9 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -318,7 +318,6 @@ static int lm85_detach_client(struct i2c_client *client); static int lm85_read_value(struct i2c_client *client, u8 reg); static void lm85_write_value(struct i2c_client *client, u8 reg, int value); static struct lm85_data *lm85_update_device(struct device *dev); -static void lm85_init_client(struct i2c_client *client); static struct i2c_driver lm85_driver = { @@ -1086,6 +1085,24 @@ static const struct attribute_group lm85_group_in567 = { .attrs = lm85_attributes_in567, }; +static void lm85_init_client(struct i2c_client *client) +{ + int value; + + /* Start monitoring if needed */ + value = lm85_read_value(client, LM85_REG_CONFIG); + if (!(value & 0x01)) { + dev_info(&client->dev, "Starting monitoring\n"); + lm85_write_value(client, LM85_REG_CONFIG, value | 0x01); + } + + /* Warn about unusual configuration bits */ + if (value & 0x02) + dev_warn(&client->dev, "Device configuration is locked\n"); + if (!(value & 0x04)) + dev_warn(&client->dev, "Device is not ready\n"); +} + static int lm85_detect(struct i2c_adapter *adapter, int address, int kind) { @@ -1330,48 +1347,6 @@ static void lm85_write_value(struct i2c_client *client, u8 reg, int value) } } -static void lm85_init_client(struct i2c_client *client) -{ - int value; - struct lm85_data *data = i2c_get_clientdata(client); - - dev_dbg(&client->dev, "Initializing device\n"); - - /* Warn if part was not "READY" */ - value = lm85_read_value(client, LM85_REG_CONFIG); - dev_dbg(&client->dev, "LM85_REG_CONFIG is: 0x%02x\n", value); - if (value & 0x02) { - dev_err(&client->dev, "Client (%d,0x%02x) config is locked.\n", - i2c_adapter_id(client->adapter), client->addr); - } - if (!(value & 0x04)) { - dev_err(&client->dev, "Client (%d,0x%02x) is not ready.\n", - i2c_adapter_id(client->adapter), client->addr); - } - if (value & 0x10 - && (data->type == adm1027 - || data->type == adt7463)) { - dev_err(&client->dev, "Client (%d,0x%02x) VxI mode is set. " - "Please report this to the lm85 maintainer.\n", - i2c_adapter_id(client->adapter), client->addr); - } - - /* WE INTENTIONALLY make no changes to the limits, - * offsets, pwms, fans and zones. If they were - * configured, we don't want to mess with them. - * If they weren't, the default is 100% PWM, no - * control and will suffice until 'sensors -s' - * can be run by the user. - */ - - /* Start monitoring */ - value = lm85_read_value(client, LM85_REG_CONFIG); - /* Try to clear LOCK, Set START, save everything else */ - value = (value & ~0x02) | 0x01; - dev_dbg(&client->dev, "Setting CONFIG to: 0x%02x\n", value); - lm85_write_value(client, LM85_REG_CONFIG, value); -} - static struct lm85_data *lm85_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); -- cgit v1.2.3 From fc1f397b2c7ef1c9bad58778e4041dfabf20c71c Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 30 Jul 2008 12:34:56 -0700 Subject: [MTD] [NAND] drivers/mtd/nand/nandsim.c needs div64.h drivers/mtd/nand/nandsim.c: In function 'divide': drivers/mtd/nand/nandsim.c:462: error: implicit declaration of function 'do_div' Cc: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/nand/nandsim.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 7428a6c1135..5d08514f553 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 963724462a11668185dc67879ea8fe7590973322 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Wed, 30 Jul 2008 12:34:57 -0700 Subject: [MTD] [NAND] diskonchip.c fix sparse endian warnings Signed-off-by: Harvey Harrison Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/nand/diskonchip.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 765d4f0f7c8..e4226e02d63 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -1125,9 +1125,9 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio goto out; mh = (struct NFTLMediaHeader *)buf; - mh->NumEraseUnits = le16_to_cpu(mh->NumEraseUnits); - mh->FirstPhysicalEUN = le16_to_cpu(mh->FirstPhysicalEUN); - mh->FormattedSize = le32_to_cpu(mh->FormattedSize); + le16_to_cpus(&mh->NumEraseUnits); + le16_to_cpus(&mh->FirstPhysicalEUN); + le32_to_cpus(&mh->FormattedSize); printk(KERN_INFO " DataOrgID = %s\n" " NumEraseUnits = %d\n" @@ -1235,12 +1235,12 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift); mh = (struct INFTLMediaHeader *)buf; - mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks); - mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions); - mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions); - mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits); - mh->FormatFlags = le32_to_cpu(mh->FormatFlags); - mh->PercentUsed = le32_to_cpu(mh->PercentUsed); + le32_to_cpus(&mh->NoOfBootImageBlocks); + le32_to_cpus(&mh->NoOfBinaryPartitions); + le32_to_cpus(&mh->NoOfBDTLPartitions); + le32_to_cpus(&mh->BlockMultiplierBits); + le32_to_cpus(&mh->FormatFlags); + le32_to_cpus(&mh->PercentUsed); printk(KERN_INFO " bootRecordID = %s\n" " NoOfBootImageBlocks = %d\n" @@ -1277,12 +1277,12 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti /* Scan the partitions */ for (i = 0; (i < 4); i++) { ip = &(mh->Partitions[i]); - ip->virtualUnits = le32_to_cpu(ip->virtualUnits); - ip->firstUnit = le32_to_cpu(ip->firstUnit); - ip->lastUnit = le32_to_cpu(ip->lastUnit); - ip->flags = le32_to_cpu(ip->flags); - ip->spareUnits = le32_to_cpu(ip->spareUnits); - ip->Reserved0 = le32_to_cpu(ip->Reserved0); + le32_to_cpus(&ip->virtualUnits); + le32_to_cpus(&ip->firstUnit); + le32_to_cpus(&ip->lastUnit); + le32_to_cpus(&ip->flags); + le32_to_cpus(&ip->spareUnits); + le32_to_cpus(&ip->Reserved0); printk(KERN_INFO " PARTITION[%d] ->\n" " virtualUnits = %d\n" -- cgit v1.2.3 From 4abb08c24b5fa7b6ad0807c07077f0f216f6788b Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Fri, 1 Aug 2008 16:39:09 +0200 Subject: [S390] dasd: Add support for enhanced VM UID When z/VM provides two virtual devices (minidisks) that reside on the same real device, both will receive the configuration data from the real device and thus get the same uid. To fix this problem, z/VM provides an additional configuration data record that allows to distinguish between minidisks. z/VM APAR VM64273 needs be installed so this fix has an effect. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_alias.c | 4 +- drivers/s390/block/dasd_devmap.c | 16 +++- drivers/s390/block/dasd_eckd.c | 147 +++++++++++++++++++++++-------- drivers/s390/block/dasd_eckd.h | 184 +++++++++++++-------------------------- drivers/s390/block/dasd_int.h | 1 + 5 files changed, 189 insertions(+), 163 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 2d8df0b3053..20676cdef4a 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -91,7 +91,8 @@ static struct alias_pav_group *_find_group(struct alias_lcu *lcu, else search_unit_addr = uid->base_unit_addr; list_for_each_entry(pos, &lcu->grouplist, group) { - if (pos->uid.base_unit_addr == search_unit_addr) + if (pos->uid.base_unit_addr == search_unit_addr && + !strncmp(pos->uid.vduit, uid->vduit, sizeof(uid->vduit))) return pos; }; return NULL; @@ -332,6 +333,7 @@ static int _add_device_to_lcu(struct alias_lcu *lcu, group->uid.base_unit_addr = uid->real_unit_addr; else group->uid.base_unit_addr = uid->base_unit_addr; + memcpy(group->uid.vduit, uid->vduit, sizeof(uid->vduit)); INIT_LIST_HEAD(&group->group); INIT_LIST_HEAD(&group->baselist); INIT_LIST_HEAD(&group->aliaslist); diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index d774e79476f..cd3335c1c30 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -913,7 +913,8 @@ dasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL); #define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial */ 14 + 1 +\ - /* SSID */ 4 + 1 + /* unit addr */ 2 + 1) + /* SSID */ 4 + 1 + /* unit addr */ 2 + 1 +\ + /* vduit */ 32 + 1) static ssize_t dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -945,8 +946,17 @@ dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) sprintf(ua_string, "%02x", uid->real_unit_addr); break; } - snprintf(uid_string, sizeof(uid_string), "%s.%s.%04x.%s", - uid->vendor, uid->serial, uid->ssid, ua_string); + if (strlen(uid->vduit) > 0) + snprintf(uid_string, sizeof(uid_string), + "%s.%s.%04x.%s.%s", + uid->vendor, uid->serial, + uid->ssid, ua_string, + uid->vduit); + else + snprintf(uid_string, sizeof(uid_string), + "%s.%s.%04x.%s", + uid->vendor, uid->serial, + uid->ssid, ua_string); spin_unlock(&dasd_devmap_lock); return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); } diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 3590fdb5b2f..773b3fe275b 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -313,8 +313,8 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk, memset(pfxdata, 0, sizeof(*pfxdata)); /* prefix data */ pfxdata->format = 0; - pfxdata->base_address = basepriv->conf_data.ned1.unit_addr; - pfxdata->base_lss = basepriv->conf_data.ned1.ID; + pfxdata->base_address = basepriv->ned->unit_addr; + pfxdata->base_lss = basepriv->ned->ID; pfxdata->validity.define_extend = 1; /* private uid is kept up to date, conf_data may be outdated */ @@ -536,36 +536,40 @@ dasd_eckd_cdl_reclen(int recid) /* * Generate device unique id that specifies the physical device. */ -static int -dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid) +static int dasd_eckd_generate_uid(struct dasd_device *device, + struct dasd_uid *uid) { struct dasd_eckd_private *private; - struct dasd_eckd_confdata *confdata; + int count; private = (struct dasd_eckd_private *) device->private; if (!private) return -ENODEV; - confdata = &private->conf_data; - if (!confdata) + if (!private->ned || !private->gneq) return -ENODEV; memset(uid, 0, sizeof(struct dasd_uid)); - memcpy(uid->vendor, confdata->ned1.HDA_manufacturer, + memcpy(uid->vendor, private->ned->HDA_manufacturer, sizeof(uid->vendor) - 1); EBCASC(uid->vendor, sizeof(uid->vendor) - 1); - memcpy(uid->serial, confdata->ned1.HDA_location, + memcpy(uid->serial, private->ned->HDA_location, sizeof(uid->serial) - 1); EBCASC(uid->serial, sizeof(uid->serial) - 1); - uid->ssid = confdata->neq.subsystemID; - uid->real_unit_addr = confdata->ned1.unit_addr; - if (confdata->ned2.sneq.flags == 0x40 && - confdata->ned2.sneq.format == 0x0001) { - uid->type = confdata->ned2.sneq.sua_flags; + uid->ssid = private->gneq->subsystemID; + uid->real_unit_addr = private->ned->unit_addr;; + if (private->sneq) { + uid->type = private->sneq->sua_flags; if (uid->type == UA_BASE_PAV_ALIAS) - uid->base_unit_addr = confdata->ned2.sneq.base_unit_addr; + uid->base_unit_addr = private->sneq->base_unit_addr; } else { uid->type = UA_BASE_DEVICE; } + if (private->vdsneq) { + for (count = 0; count < 16; count++) { + sprintf(uid->vduit+2*count, "%02x", + private->vdsneq->uit[count]); + } + } return 0; } @@ -623,6 +627,15 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device, ret = -ENOMEM; goto out_error; } + + /* + * buffer has to start with EBCDIC "V1.0" to show + * support for virtual device SNEQ + */ + rcd_buf[0] = 0xE5; + rcd_buf[1] = 0xF1; + rcd_buf[2] = 0x4B; + rcd_buf[3] = 0xF0; cqr = dasd_eckd_build_rcd_lpm(device, rcd_buf, ciw, lpm); if (IS_ERR(cqr)) { ret = PTR_ERR(cqr); @@ -646,8 +659,62 @@ out_error: return ret; } -static int -dasd_eckd_read_conf(struct dasd_device *device) +static int dasd_eckd_identify_conf_parts(struct dasd_eckd_private *private) +{ + + struct dasd_sneq *sneq; + int i, count; + + private->ned = NULL; + private->sneq = NULL; + private->vdsneq = NULL; + private->gneq = NULL; + count = private->conf_len / sizeof(struct dasd_sneq); + sneq = (struct dasd_sneq *)private->conf_data; + for (i = 0; i < count; ++i) { + if (sneq->flags.identifier == 1 && sneq->format == 1) + private->sneq = sneq; + else if (sneq->flags.identifier == 1 && sneq->format == 4) + private->vdsneq = (struct vd_sneq *)sneq; + else if (sneq->flags.identifier == 2) + private->gneq = (struct dasd_gneq *)sneq; + else if (sneq->flags.identifier == 3 && sneq->res1 == 1) + private->ned = (struct dasd_ned *)sneq; + sneq++; + } + if (!private->ned || !private->gneq) { + private->ned = NULL; + private->sneq = NULL; + private->vdsneq = NULL; + private->gneq = NULL; + return -EINVAL; + } + return 0; + +}; + +static unsigned char dasd_eckd_path_access(void *conf_data, int conf_len) +{ + struct dasd_gneq *gneq; + int i, count, found; + + count = conf_len / sizeof(*gneq); + gneq = (struct dasd_gneq *)conf_data; + found = 0; + for (i = 0; i < count; ++i) { + if (gneq->flags.identifier == 2) { + found = 1; + break; + } + gneq++; + } + if (found) + return ((char *)gneq)[18] & 0x07; + else + return 0; +} + +static int dasd_eckd_read_conf(struct dasd_device *device) { void *conf_data; int conf_len, conf_data_saved; @@ -661,7 +728,6 @@ dasd_eckd_read_conf(struct dasd_device *device) path_data->opm = ccw_device_get_path_mask(device->cdev); lpm = 0x80; conf_data_saved = 0; - /* get configuration data per operational path */ for (lpm = 0x80; lpm; lpm>>= 1) { if (lpm & path_data->opm){ @@ -678,22 +744,20 @@ dasd_eckd_read_conf(struct dasd_device *device) "data retrieved"); continue; /* no error */ } - if (conf_len != sizeof(struct dasd_eckd_confdata)) { - MESSAGE(KERN_WARNING, - "sizes of configuration data mismatch" - "%d (read) vs %ld (expected)", - conf_len, - sizeof(struct dasd_eckd_confdata)); - kfree(conf_data); - continue; /* no error */ - } /* save first valid configuration data */ - if (!conf_data_saved){ - memcpy(&private->conf_data, conf_data, - sizeof(struct dasd_eckd_confdata)); + if (!conf_data_saved) { + kfree(private->conf_data); + private->conf_data = conf_data; + private->conf_len = conf_len; + if (dasd_eckd_identify_conf_parts(private)) { + private->conf_data = NULL; + private->conf_len = 0; + kfree(conf_data); + continue; + } conf_data_saved++; } - switch (((char *)conf_data)[242] & 0x07){ + switch (dasd_eckd_path_access(conf_data, conf_len)) { case 0x02: path_data->npm |= lpm; break; @@ -701,7 +765,8 @@ dasd_eckd_read_conf(struct dasd_device *device) path_data->ppm |= lpm; break; } - kfree(conf_data); + if (conf_data != private->conf_data) + kfree(conf_data); } } return 0; @@ -952,6 +1017,7 @@ out_err2: dasd_free_block(device->block); device->block = NULL; out_err1: + kfree(private->conf_data); kfree(device->private); device->private = NULL; return rc; @@ -959,7 +1025,17 @@ out_err1: static void dasd_eckd_uncheck_device(struct dasd_device *device) { + struct dasd_eckd_private *private; + + private = (struct dasd_eckd_private *) device->private; dasd_alias_disconnect_device_from_lcu(device); + private->ned = NULL; + private->sneq = NULL; + private->vdsneq = NULL; + private->gneq = NULL; + private->conf_len = 0; + kfree(private->conf_data); + private->conf_data = NULL; } static struct dasd_ccw_req * @@ -1746,9 +1822,10 @@ dasd_eckd_fill_info(struct dasd_device * device, info->characteristics_size = sizeof(struct dasd_eckd_characteristics); memcpy(info->characteristics, &private->rdc_data, sizeof(struct dasd_eckd_characteristics)); - info->confdata_size = sizeof(struct dasd_eckd_confdata); - memcpy(info->configuration_data, &private->conf_data, - sizeof(struct dasd_eckd_confdata)); + info->confdata_size = min((unsigned long)private->conf_len, + sizeof(info->configuration_data)); + memcpy(info->configuration_data, private->conf_data, + info->confdata_size); return 0; } diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index fc2509c939b..4bf0aa5112c 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -231,133 +231,62 @@ struct dasd_eckd_characteristics { __u8 reserved3[10]; } __attribute__ ((packed)); -struct dasd_eckd_confdata { +/* elements of the configuration data */ +struct dasd_ned { struct { - struct { - unsigned char identifier:2; - unsigned char token_id:1; - unsigned char sno_valid:1; - unsigned char subst_sno:1; - unsigned char recNED:1; - unsigned char emuNED:1; - unsigned char reserved:1; - } __attribute__ ((packed)) flags; - __u8 descriptor; - __u8 dev_class; - __u8 reserved; - unsigned char dev_type[6]; - unsigned char dev_model[3]; - unsigned char HDA_manufacturer[3]; - unsigned char HDA_location[2]; - unsigned char HDA_seqno[12]; - __u8 ID; - __u8 unit_addr; - } __attribute__ ((packed)) ned1; - union { - struct { - struct { - unsigned char identifier:2; - unsigned char token_id:1; - unsigned char sno_valid:1; - unsigned char subst_sno:1; - unsigned char recNED:1; - unsigned char emuNED:1; - unsigned char reserved:1; - } __attribute__ ((packed)) flags; - __u8 descriptor; - __u8 reserved[2]; - unsigned char dev_type[6]; - unsigned char dev_model[3]; - unsigned char DASD_manufacturer[3]; - unsigned char DASD_location[2]; - unsigned char DASD_seqno[12]; - __u16 ID; - } __attribute__ ((packed)) ned; - struct { - unsigned char flags; /* byte 0 */ - unsigned char res1; /* byte 1 */ - __u16 format; /* byte 2-3 */ - unsigned char res2[4]; /* byte 4-7 */ - unsigned char sua_flags; /* byte 8 */ - __u8 base_unit_addr; /* byte 9 */ - unsigned char res3[22]; /* byte 10-31 */ - } __attribute__ ((packed)) sneq; - } __attribute__ ((packed)) ned2; + __u8 identifier:2; + __u8 token_id:1; + __u8 sno_valid:1; + __u8 subst_sno:1; + __u8 recNED:1; + __u8 emuNED:1; + __u8 reserved:1; + } __attribute__ ((packed)) flags; + __u8 descriptor; + __u8 dev_class; + __u8 reserved; + __u8 dev_type[6]; + __u8 dev_model[3]; + __u8 HDA_manufacturer[3]; + __u8 HDA_location[2]; + __u8 HDA_seqno[12]; + __u8 ID; + __u8 unit_addr; +} __attribute__ ((packed)); + +struct dasd_sneq { struct { - struct { - unsigned char identifier:2; - unsigned char token_id:1; - unsigned char sno_valid:1; - unsigned char subst_sno:1; - unsigned char recNED:1; - unsigned char emuNED:1; - unsigned char reserved:1; - } __attribute__ ((packed)) flags; - __u8 descriptor; - __u8 reserved[2]; - unsigned char cont_type[6]; - unsigned char cont_model[3]; - unsigned char cont_manufacturer[3]; - unsigned char cont_location[2]; - unsigned char cont_seqno[12]; - __u16 ID; - } __attribute__ ((packed)) ned3; + __u8 identifier:2; + __u8 reserved:6; + } __attribute__ ((packed)) flags; + __u8 res1; + __u16 format; + __u8 res2[4]; /* byte 4- 7 */ + __u8 sua_flags; /* byte 8 */ + __u8 base_unit_addr; /* byte 9 */ + __u8 res3[22]; /* byte 10-31 */ +} __attribute__ ((packed)); + +struct vd_sneq { struct { - struct { - unsigned char identifier:2; - unsigned char token_id:1; - unsigned char sno_valid:1; - unsigned char subst_sno:1; - unsigned char recNED:1; - unsigned char emuNED:1; - unsigned char reserved:1; - } __attribute__ ((packed)) flags; - __u8 descriptor; - __u8 reserved[2]; - unsigned char cont_type[6]; - unsigned char empty[3]; - unsigned char cont_manufacturer[3]; - unsigned char cont_location[2]; - unsigned char cont_seqno[12]; - __u16 ID; - } __attribute__ ((packed)) ned4; - unsigned char ned5[32]; - unsigned char ned6[32]; - unsigned char ned7[32]; + __u8 identifier:2; + __u8 reserved:6; + } __attribute__ ((packed)) flags; + __u8 res1; + __u16 format; + __u8 res2[4]; /* byte 4- 7 */ + __u8 uit[16]; /* byte 8-23 */ + __u8 res3[8]; /* byte 24-31 */ +} __attribute__ ((packed)); + +struct dasd_gneq { struct { - struct { - unsigned char identifier:2; - unsigned char reserved:6; - } __attribute__ ((packed)) flags; - __u8 selector; - __u16 interfaceID; - __u32 reserved; - __u16 subsystemID; - struct { - unsigned char sp0:1; - unsigned char sp1:1; - unsigned char reserved:5; - unsigned char scluster:1; - } __attribute__ ((packed)) spathID; - __u8 unit_address; - __u8 dev_ID; - __u8 dev_address; - __u8 adapterID; - __u16 link_address; - struct { - unsigned char parallel:1; - unsigned char escon:1; - unsigned char reserved:1; - unsigned char ficon:1; - unsigned char reserved2:4; - } __attribute__ ((packed)) protocol_type; - struct { - unsigned char PID_in_236:1; - unsigned char reserved:7; - } __attribute__ ((packed)) format_flags; - __u8 log_dev_address; - unsigned char reserved2[12]; - } __attribute__ ((packed)) neq; + __u8 identifier:2; + __u8 reserved:6; + } __attribute__ ((packed)) flags; + __u8 reserved[7]; + __u16 subsystemID; + __u8 reserved2[22]; } __attribute__ ((packed)); struct dasd_eckd_path { @@ -463,7 +392,14 @@ struct alias_pav_group { struct dasd_eckd_private { struct dasd_eckd_characteristics rdc_data; - struct dasd_eckd_confdata conf_data; + u8 *conf_data; + int conf_len; + /* pointers to specific parts in the conf_data */ + struct dasd_ned *ned; + struct dasd_sneq *sneq; + struct vd_sneq *vdsneq; + struct dasd_gneq *gneq; + struct dasd_eckd_path path_data; struct eckd_count count_area[5]; int init_cqr_status; diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index fb2f931cf84..31ecaa4a40e 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -307,6 +307,7 @@ struct dasd_uid { __u16 ssid; __u8 real_unit_addr; __u8 base_unit_addr; + char vduit[33]; }; /* -- cgit v1.2.3 From 934b2857cc576ae53c92a66e63fce7ddcfa74691 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 1 Aug 2008 16:39:11 +0200 Subject: [S390] nohz/sclp: disable timer on synchronous waits. sclp_sync_wait wait synchronously for an sclp interrupt and disables timer interrupts. However on the irq enter paths there is an extra check if a timer interrupt would be due and calls the timer callback. This would schedule softirqs in the wrong context. So introduce local_tick_enable/disable which prevents this. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 3c8b25e6c34..1fd8f2193ed 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -399,6 +399,7 @@ sclp_tod_from_jiffies(unsigned long jiffies) void sclp_sync_wait(void) { + unsigned long long old_tick; unsigned long flags; unsigned long cr0, cr0_sync; u64 timeout; @@ -419,11 +420,12 @@ sclp_sync_wait(void) if (!irq_context) local_bh_disable(); /* Enable service-signal interruption, disable timer interrupts */ + old_tick = local_tick_disable(); trace_hardirqs_on(); __ctl_store(cr0, 0, 0); cr0_sync = cr0; + cr0_sync &= 0xffff00a0; cr0_sync |= 0x00000200; - cr0_sync &= 0xFFFFF3AC; __ctl_load(cr0_sync, 0, 0); __raw_local_irq_stosm(0x01); /* Loop until driver state indicates finished request */ @@ -439,9 +441,9 @@ sclp_sync_wait(void) __ctl_load(cr0, 0, 0); if (!irq_context) _local_bh_enable(); + local_tick_enable(old_tick); local_irq_restore(flags); } - EXPORT_SYMBOL(sclp_sync_wait); /* Dispatch changes in send and receive mask to registered listeners. */ -- cgit v1.2.3 From 683d718a893575a88c551ad71ea2c382eedbf67e Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Fri, 1 Aug 2008 16:39:13 +0200 Subject: [S390] qeth: preallocated qeth header for hiper socket For hiper socket devices this patch will economize the reallocation of the tx skb data segment by allocating separate memory for the qdio transport information (qeth header). Signed-off-by: Frank Blaschka Signed-off-by: Martin Schwidefsky --- drivers/s390/net/qeth_core.h | 5 ++-- drivers/s390/net/qeth_core_main.c | 59 ++++++++++++++++++++++++++++++--------- drivers/s390/net/qeth_l2_main.c | 50 +++++++++++++++++++++++++-------- drivers/s390/net/qeth_l3_main.c | 51 ++++++++++++++++++++++++--------- 4 files changed, 126 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 1895dbb553c..80971c21ea1 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -419,6 +419,7 @@ struct qeth_qdio_out_buffer { int next_element_to_fill; struct sk_buff_head skb_list; struct list_head ctx_list; + int is_header[16]; }; struct qeth_card; @@ -785,7 +786,7 @@ void qeth_core_remove_osn_attributes(struct device *); /* exports for qeth discipline device drivers */ extern struct qeth_card_list_struct qeth_core_card_list; - +extern struct kmem_cache *qeth_core_header_cache; extern struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS]; void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int); @@ -843,7 +844,7 @@ int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int); int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int); int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *, struct sk_buff *, struct qeth_hdr *, int, - struct qeth_eddp_context *); + struct qeth_eddp_context *, int, int); int qeth_do_send_packet(struct qeth_card *, struct qeth_qdio_out_q *, struct sk_buff *, struct qeth_hdr *, int, struct qeth_eddp_context *); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index cebb25e36e8..7a554991971 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -48,6 +48,8 @@ EXPORT_SYMBOL_GPL(qeth_dbf); struct qeth_card_list_struct qeth_core_card_list; EXPORT_SYMBOL_GPL(qeth_core_card_list); +struct kmem_cache *qeth_core_header_cache; +EXPORT_SYMBOL_GPL(qeth_core_header_cache); static struct device *qeth_core_root_dev; static unsigned int known_devices[][10] = QETH_MODELLIST_ARRAY; @@ -933,6 +935,10 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, } qeth_eddp_buf_release_contexts(buf); for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i) { + if (buf->buffer->element[i].addr && buf->is_header[i]) + kmem_cache_free(qeth_core_header_cache, + buf->buffer->element[i].addr); + buf->is_header[i] = 0; buf->buffer->element[i].length = 0; buf->buffer->element[i].addr = NULL; buf->buffer->element[i].flags = 0; @@ -3002,8 +3008,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr, if (skb_shinfo(skb)->nr_frags > 0) elements_needed = (skb_shinfo(skb)->nr_frags + 1); if (elements_needed == 0) - elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) - + skb->len) >> PAGE_SHIFT); + elements_needed = 1 + (((((unsigned long) skb->data) % + PAGE_SIZE) + skb->len) >> PAGE_SHIFT); if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { QETH_DBF_MESSAGE(2, "Invalid size of IP packet " "(Number=%d / Length=%d). Discarded.\n", @@ -3015,7 +3021,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr, EXPORT_SYMBOL_GPL(qeth_get_elements_no); static inline void __qeth_fill_buffer(struct sk_buff *skb, - struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill) + struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill, + int offset) { int length = skb->len; int length_here; @@ -3027,6 +3034,11 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb, data = skb->data; first_lap = (is_tso == 0 ? 1 : 0); + if (offset >= 0) { + data = skb->data + offset; + first_lap = 0; + } + while (length > 0) { /* length_here is the remaining amount of data in this page */ length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE); @@ -3058,22 +3070,22 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb, } static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, - struct qeth_qdio_out_buffer *buf, struct sk_buff *skb) + struct qeth_qdio_out_buffer *buf, struct sk_buff *skb, + struct qeth_hdr *hdr, int offset, int hd_len) { struct qdio_buffer *buffer; - struct qeth_hdr_tso *hdr; int flush_cnt = 0, hdr_len, large_send = 0; buffer = buf->buffer; atomic_inc(&skb->users); skb_queue_tail(&buf->skb_list, skb); - hdr = (struct qeth_hdr_tso *) skb->data; /*check first on TSO ....*/ - if (hdr->hdr.hdr.l3.id == QETH_HEADER_TYPE_TSO) { + if (hdr->hdr.l3.id == QETH_HEADER_TYPE_TSO) { int element = buf->next_element_to_fill; - hdr_len = sizeof(struct qeth_hdr_tso) + hdr->ext.dg_hdr_len; + hdr_len = sizeof(struct qeth_hdr_tso) + + ((struct qeth_hdr_tso *)hdr)->ext.dg_hdr_len; /*fill first buffer entry only with header information */ buffer->element[element].addr = skb->data; buffer->element[element].length = hdr_len; @@ -3083,9 +3095,20 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, skb->len -= hdr_len; large_send = 1; } + + if (offset >= 0) { + int element = buf->next_element_to_fill; + buffer->element[element].addr = hdr; + buffer->element[element].length = sizeof(struct qeth_hdr) + + hd_len; + buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG; + buf->is_header[element] = 1; + buf->next_element_to_fill++; + } + if (skb_shinfo(skb)->nr_frags == 0) __qeth_fill_buffer(skb, buffer, large_send, - (int *)&buf->next_element_to_fill); + (int *)&buf->next_element_to_fill, offset); else __qeth_fill_buffer_frag(skb, buffer, large_send, (int *)&buf->next_element_to_fill); @@ -3115,7 +3138,7 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, int qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue, struct sk_buff *skb, struct qeth_hdr *hdr, int elements_needed, - struct qeth_eddp_context *ctx) + struct qeth_eddp_context *ctx, int offset, int hd_len) { struct qeth_qdio_out_buffer *buffer; int buffers_needed = 0; @@ -3148,7 +3171,7 @@ int qeth_do_send_packet_fast(struct qeth_card *card, } atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); if (ctx == NULL) { - qeth_fill_buffer(queue, buffer, skb); + qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len); qeth_flush_buffers(queue, index, 1); } else { flush_cnt = qeth_eddp_fill_buffer(queue, ctx, index); @@ -3224,7 +3247,7 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, } } if (ctx == NULL) - tmp = qeth_fill_buffer(queue, buffer, skb); + tmp = qeth_fill_buffer(queue, buffer, skb, hdr, -1, 0); else { tmp = qeth_eddp_fill_buffer(queue, ctx, queue->next_buf_to_fill); @@ -4443,8 +4466,17 @@ static int __init qeth_core_init(void) rc = IS_ERR(qeth_core_root_dev) ? PTR_ERR(qeth_core_root_dev) : 0; if (rc) goto register_err; - return 0; + qeth_core_header_cache = kmem_cache_create("qeth_hdr", + sizeof(struct qeth_hdr) + ETH_HLEN, 64, 0, NULL); + if (!qeth_core_header_cache) { + rc = -ENOMEM; + goto slab_err; + } + + return 0; +slab_err: + s390_root_dev_unregister(qeth_core_root_dev); register_err: driver_remove_file(&qeth_core_ccwgroup_driver.driver, &driver_attr_group); @@ -4466,6 +4498,7 @@ static void __exit qeth_core_exit(void) &driver_attr_group); ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver); ccw_driver_unregister(&qeth_ccw_driver); + kmem_cache_destroy(qeth_core_header_cache); qeth_unregister_dbf_views(); PRINT_INFO("core functions removed\n"); } diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index a8b069cd9a4..b3cee032f57 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -243,8 +243,7 @@ static void qeth_l2_get_packet_type(struct qeth_card *card, static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, struct sk_buff *skb, int ipv, int cast_type) { - struct vlan_ethhdr *veth = (struct vlan_ethhdr *)((skb->data) + - QETH_HEADER_SIZE); + struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb); memset(hdr, 0, sizeof(struct qeth_hdr)); hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2; @@ -621,6 +620,9 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) int tx_bytes = skb->len; enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; struct qeth_eddp_context *ctx = NULL; + int data_offset = -1; + int elements_needed = 0; + int hd_len = 0; if ((card->state != CARD_STATE_UP) || !card->lan_online) { card->stats.tx_carrier_errors++; @@ -643,13 +645,32 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (card->info.type == QETH_CARD_TYPE_OSN) hdr = (struct qeth_hdr *)skb->data; else { - /* create a clone with writeable headroom */ - new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr)); - if (!new_skb) - goto tx_drop; - hdr = (struct qeth_hdr *)skb_push(new_skb, + if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) && + (skb_shinfo(skb)->nr_frags == 0)) { + new_skb = skb; + data_offset = ETH_HLEN; + hd_len = ETH_HLEN; + hdr = kmem_cache_alloc(qeth_core_header_cache, + GFP_ATOMIC); + if (!hdr) + goto tx_drop; + elements_needed++; + skb_reset_mac_header(new_skb); + qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type); + hdr->hdr.l2.pkt_length = new_skb->len; + memcpy(((char *)hdr) + sizeof(struct qeth_hdr), + skb_mac_header(new_skb), ETH_HLEN); + } else { + /* create a clone with writeable headroom */ + new_skb = skb_realloc_headroom(skb, + sizeof(struct qeth_hdr)); + if (!new_skb) + goto tx_drop; + hdr = (struct qeth_hdr *)skb_push(new_skb, sizeof(struct qeth_hdr)); - qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type); + skb_set_mac_header(new_skb, sizeof(struct qeth_hdr)); + qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type); + } } if (large_send == QETH_LARGE_SEND_EDDP) { @@ -660,9 +681,13 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) goto tx_drop; } } else { - elements = qeth_get_elements_no(card, (void *)hdr, new_skb, 0); - if (!elements) + elements = qeth_get_elements_no(card, (void *)hdr, new_skb, + elements_needed); + if (!elements) { + if (data_offset >= 0) + kmem_cache_free(qeth_core_header_cache, hdr); goto tx_drop; + } } if ((large_send == QETH_LARGE_SEND_NO) && @@ -674,7 +699,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) elements, ctx); else rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, - elements, ctx); + elements, ctx, data_offset, hd_len); if (!rc) { card->stats.tx_packets++; card->stats.tx_bytes += tx_bytes; @@ -701,6 +726,9 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (ctx != NULL) qeth_eddp_put_context(ctx); + if (data_offset >= 0) + kmem_cache_free(qeth_core_header_cache, hdr); + if (rc == -EBUSY) { if (new_skb != skb) dev_kfree_skb_any(new_skb); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 3e1d1385735..dd72c3c2016 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2604,6 +2604,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) int tx_bytes = skb->len; enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; struct qeth_eddp_context *ctx = NULL; + int data_offset = -1; if ((card->info.type == QETH_CARD_TYPE_IQD) && (skb->protocol != htons(ETH_P_IPV6)) && @@ -2624,14 +2625,28 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) card->perf_stats.outbound_start_time = qeth_get_micros(); } - /* create a clone with writeable headroom */ - new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr_tso) + - VLAN_HLEN); - if (!new_skb) - goto tx_drop; + if (skb_is_gso(skb)) + large_send = card->options.large_send; + + if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) && + (skb_shinfo(skb)->nr_frags == 0)) { + new_skb = skb; + data_offset = ETH_HLEN; + hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC); + if (!hdr) + goto tx_drop; + elements_needed++; + } else { + /* create a clone with writeable headroom */ + new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr_tso) + + VLAN_HLEN); + if (!new_skb) + goto tx_drop; + } if (card->info.type == QETH_CARD_TYPE_IQD) { - skb_pull(new_skb, ETH_HLEN); + if (data_offset < 0) + skb_pull(new_skb, ETH_HLEN); } else { if (new_skb->protocol == htons(ETH_P_IP)) { if (card->dev->type == ARPHRD_IEEE802_TR) @@ -2657,9 +2672,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); - if (skb_is_gso(new_skb)) - large_send = card->options.large_send; - /* fix hardware limitation: as long as we do not have sbal * chaining we can not send long frag lists so we temporary * switch to EDDP @@ -2677,9 +2689,16 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) qeth_tso_fill_header(card, hdr, new_skb); elements_needed++; } else { - hdr = (struct qeth_hdr *)skb_push(new_skb, + if (data_offset < 0) { + hdr = (struct qeth_hdr *)skb_push(new_skb, sizeof(struct qeth_hdr)); - qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); + qeth_l3_fill_header(card, hdr, new_skb, ipv, + cast_type); + } else { + qeth_l3_fill_header(card, hdr, new_skb, ipv, + cast_type); + hdr->hdr.l3.length = new_skb->len - data_offset; + } } if (large_send == QETH_LARGE_SEND_EDDP) { @@ -2695,8 +2714,11 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } else { int elems = qeth_get_elements_no(card, (void *)hdr, new_skb, elements_needed); - if (!elems) + if (!elems) { + if (data_offset >= 0) + kmem_cache_free(qeth_core_header_cache, hdr); goto tx_drop; + } elements_needed += elems; } @@ -2709,7 +2731,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) elements_needed, ctx); else rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, - elements_needed, ctx); + elements_needed, ctx, data_offset, 0); if (!rc) { card->stats.tx_packets++; @@ -2737,6 +2759,9 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (ctx != NULL) qeth_eddp_put_context(ctx); + if (data_offset >= 0) + kmem_cache_free(qeth_core_header_cache, hdr); + if (rc == -EBUSY) { if (new_skb != skb) dev_kfree_skb_any(new_skb); -- cgit v1.2.3 From 883e512c99fc398d1b2b5e8e92b6bacff2551756 Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Fri, 1 Aug 2008 16:39:14 +0200 Subject: [S390] cio: Memory allocation for idset changed. Memory allocation for the quite huge idset changed from kzalloc to vmalloc. Signed-off-by: Michael Ernst Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/idset.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c index ef7bc0a125e..cf8f24a4b5e 100644 --- a/drivers/s390/cio/idset.c +++ b/drivers/s390/cio/idset.c @@ -5,7 +5,7 @@ * Author(s): Peter Oberparleiter */ -#include +#include #include #include "idset.h" #include "css.h" @@ -25,18 +25,18 @@ static struct idset *idset_new(int num_ssid, int num_id) { struct idset *set; - set = kzalloc(sizeof(struct idset) + bitmap_size(num_ssid, num_id), - GFP_KERNEL); + set = vmalloc(sizeof(struct idset) + bitmap_size(num_ssid, num_id)); if (set) { set->num_ssid = num_ssid; set->num_id = num_id; + memset(set->bitmap, 0, bitmap_size(num_ssid, num_id)); } return set; } void idset_free(struct idset *set) { - kfree(set); + vfree(set); } void idset_clear(struct idset *set) -- cgit v1.2.3 From 7e9238fbc10373effc2c3b0b516b0bdc8fefc27b Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Fri, 1 Aug 2008 16:39:16 +0200 Subject: [S390] Add support for memory hot-remove. This patch enables memory hot-remove on s390. Signed-off-by: Gerald Schaefer Signed-off-by: Heiko Carstens Cc: Martin Schwidefsky --- drivers/s390/char/sclp_cmd.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 0c2b77493db..eb5f1b8bc57 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -427,6 +427,8 @@ static int sclp_mem_notifier(struct notifier_block *nb, sclp_attach_storage(id); switch (action) { case MEM_ONLINE: + case MEM_GOING_OFFLINE: + case MEM_CANCEL_OFFLINE: break; case MEM_GOING_ONLINE: rc = sclp_mem_change_state(start, size, 1); @@ -434,6 +436,9 @@ static int sclp_mem_notifier(struct notifier_block *nb, case MEM_CANCEL_ONLINE: sclp_mem_change_state(start, size, 0); break; + case MEM_OFFLINE: + sclp_mem_change_state(start, size, 0); + break; default: rc = -EINVAL; break; -- cgit v1.2.3 From 3b8e3004aea95c687e8991583e7b150ec1416ff3 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Fri, 1 Aug 2008 16:39:17 +0200 Subject: [S390] qdio: make sure qdr is aligned to page size kzalloc does not guarantee the required alignment of qdr to page size, use get_zeroed_page instead. Signed-off-by: Jan Glauber --- drivers/s390/cio/qdio_main.c | 2 +- drivers/s390/cio/qdio_setup.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index d10c73cc168..d15648514a0 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -1355,7 +1355,7 @@ int qdio_allocate(struct qdio_initialize *init_data) goto out_rel; /* qdr is used in ccw1.cda which is u32 */ - irq_ptr->qdr = kzalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA); + irq_ptr->qdr = (struct qdr *) get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!irq_ptr->qdr) goto out_rel; WARN_ON((unsigned long)irq_ptr->qdr & 0xfff); diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index f0923a8aced..56fdd57ba19 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -325,7 +325,7 @@ void qdio_release_memory(struct qdio_irq *irq_ptr) kmem_cache_free(qdio_q_cache, q); } } - kfree(irq_ptr->qdr); + free_page((unsigned long) irq_ptr->qdr); free_page(irq_ptr->chsc_page); free_page((unsigned long) irq_ptr); } -- cgit v1.2.3 From 3f1934bc1a0dcc2b7c31c8fd4f41ea2dd6522c3e Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 1 Aug 2008 16:39:20 +0200 Subject: [S390] qdio: fix section mismatch bug. Fix the two section mismatch warnings below. This fixes two real bugs since the code which has __exit annotations may already be gone when it is called. WARNING: vmlinux.o(.init.text+0x1cc4a): Section mismatch in reference from the function init_QDIO() to the function .exit.text:qdio_setup_exit() The function __init init_QDIO() references a function __exit qdio_setup_exit(). This is often seen when error handling in the init function uses functionality in the exit path. The fix is often to remove the __exit annotation of qdio_setup_exit() so it may be used outside an exit section. WARNING: vmlinux.o(.init.text+0x1cc7a): Section mismatch in reference from the function init_QDIO() to the function .exit.text:qdio_remove_perf_stats() The function __init init_QDIO() references a function __exit qdio_remove_perf_stats(). This is often seen when error handling in the init function uses functionality in the exit path. The fix is often to remove the __exit annotation of qdio_remove_perf_stats() so it may be used outside an exit section. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_perf.c | 2 +- drivers/s390/cio/qdio_setup.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/qdio_perf.c b/drivers/s390/cio/qdio_perf.c index ea01b85b1cc..ec5c4a41423 100644 --- a/drivers/s390/cio/qdio_perf.c +++ b/drivers/s390/cio/qdio_perf.c @@ -142,7 +142,7 @@ int __init qdio_setup_perf_stats(void) return 0; } -void __exit qdio_remove_perf_stats(void) +void qdio_remove_perf_stats(void) { #ifdef CONFIG_PROC_FS remove_proc_entry("qdio_perf", NULL); diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 56fdd57ba19..1bd2a208db2 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -515,7 +515,7 @@ int __init qdio_setup_init(void) return 0; } -void __exit qdio_setup_exit(void) +void qdio_setup_exit(void) { kmem_cache_destroy(qdio_q_cache); } -- cgit v1.2.3 From 26f746f3e3bb44b37a894318aa8e808b914ad663 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 1 Aug 2008 16:39:22 +0200 Subject: [S390] virtio console: fix section mismatch warning. Fix these two false positive warnings: WARNING: vmlinux.o(.text+0x2e1cc4): Section mismatch in reference from the function s390_virtio_console_init() to the function .init.text:early_put_chars() The function s390_virtio_console_init() references the function __init early_put_chars(). This is often because s390_virtio_console_init lacks a __init annotation or the annotation of early_put_chars is wrong. WARNING: vmlinux.o(.text+0x2e1cd0): Section mismatch in reference from the function s390_virtio_console_init() to the function .init.text:virtio_cons_early_init() The function s390_virtio_console_init() references the function __init virtio_cons_early_init(). This is often because s390_virtio_console_init lacks a __init annotation or the annotation of virtio_cons_early_init is wrong. Cc: Christian Borntraeger Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/kvm/kvm_virtio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 79954bd6bfa..292b60da6dc 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -352,7 +352,7 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count) return len; } -void s390_virtio_console_init(void) +void __init s390_virtio_console_init(void) { virtio_cons_early_init(early_put_chars); } -- cgit v1.2.3 From fc7e1e4b1ca69109d0f694e47ef2328dcb0ebe6e Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 1 Aug 2008 16:39:23 +0200 Subject: [S390] dont use kthread for smp_rescan_cpus(). Since git commit 3da1c84c00c7e5fa8348336bd8c342f9128b0f14 "workqueues: make get_online_cpus() useable for work->func()" it is safe to call get_online_cpus() from workqueue context. So remove the kthread workaround again. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp_config.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c index fff4ff485d9..4cebd6ee6d2 100644 --- a/drivers/s390/char/sclp_config.c +++ b/drivers/s390/char/sclp_config.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -41,19 +40,9 @@ static void sclp_cpu_capability_notify(struct work_struct *work) put_online_cpus(); } -static int sclp_cpu_kthread(void *data) -{ - smp_rescan_cpus(); - return 0; -} - static void __ref sclp_cpu_change_notify(struct work_struct *work) { - /* Can't call smp_rescan_cpus() from workqueue context since it may - * deadlock in case of cpu hotplug. So we have to create a kernel - * thread in order to call it. - */ - kthread_run(sclp_cpu_kthread, NULL, "cpu_rescan"); + smp_rescan_cpus(); } static void sclp_conf_receiver_fn(struct evbuf_header *evbuf) -- cgit v1.2.3 From ab4227cb2d936886069ef1056c02500d05beb15d Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 1 Aug 2008 16:39:24 +0200 Subject: [S390] qeth: avoid use of include/asm-s390 The planned move of include/asm-s390 to arch/s390/include/asm requires that all includes for asm headers use include/asm and not include/asm-s390. Signed-off-by: Martin Schwidefsky --- drivers/s390/net/qeth_core_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 7a554991971..bd420d1b9a0 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -19,8 +19,8 @@ #include #include -#include -#include +#include +#include #include #include "qeth_core.h" -- cgit v1.2.3 From e274f025e2caaadc1a6dd41adc9c9a19be075110 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 30 Jul 2008 12:34:59 -0700 Subject: [MTD] [NAND] Blackfin NFC Driver: fix bug - do not clobber the status from the first 256 bytes if operating on 512 pages Singed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/nand/bf5xx_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index e87a5729732..3254348f858 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -273,7 +273,7 @@ static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat, dat += 256; read_ecc += 8; calc_ecc += 8; - ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); + ret |= bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); } return ret; -- cgit v1.2.3 From cf840392e83914b9fcdbce8a8a2bc17a84cf0353 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 30 Jul 2008 12:35:00 -0700 Subject: [MTD] [NAND] Blackfin NFC Driver: fix bug - hw ecc calc by making sure we extract 11 bits from each register instead of 10 Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/nand/bf5xx_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 3254348f858..fc58afe4733 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -298,7 +298,7 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd, ecc0 = bfin_read_NFC_ECC0(); ecc1 = bfin_read_NFC_ECC1(); - code[0] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11); + code[0] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11); dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]); @@ -310,7 +310,7 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd, if (page_size == 512) { ecc0 = bfin_read_NFC_ECC2(); ecc1 = bfin_read_NFC_ECC3(); - code[1] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11); + code[1] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11); /* second 3 bytes in ecc_code for second 256 * bytes of 512 page size -- cgit v1.2.3 From fcb90ba7e9ba9a17ca5103be3f3ae3a446dadc14 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 30 Jul 2008 12:35:01 -0700 Subject: [MTD] [NAND] Blackfin NFC Driver: add support for the ECC layout the Blackfin bootrom uses Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/nand/Kconfig | 12 ++++++++++++ drivers/mtd/nand/bf5xx_nand.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 71406e51785..c075b47e11a 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -109,6 +109,18 @@ config MTD_NAND_BF5XX_HWECC Enable the use of the BF5XX's internal ECC generator when using NAND. +config MTD_NAND_BF5XX_BOOTROM_ECC + bool "Use Blackfin BootROM ECC Layout" + default n + depends on MTD_NAND_BF5XX_HWECC + help + If you wish to modify NAND pages and allow the Blackfin on-chip + BootROM to boot from them, say Y here. This is only necessary + if you are booting U-Boot out of NAND and you wish to update + U-Boot from Linux' userspace. Otherwise, you should say N here. + + If unsure, say N. + config MTD_NAND_RTC_FROM4 tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)" depends on SH_SOLUTION_ENGINE diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index fc58afe4733..3555f6b3ebe 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -91,6 +91,41 @@ static const unsigned short bfin_nfc_pin_req[] = P_NAND_ALE, 0}; +#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC +static uint8_t bbt_pattern[] = { 0xff }; + +static struct nand_bbt_descr bootrom_bbt = { + .options = 0, + .offs = 63, + .len = 1, + .pattern = bbt_pattern, +}; + +static struct nand_ecclayout bootrom_ecclayout = { + .eccbytes = 24, + .eccpos = { + 0x8 * 0, 0x8 * 0 + 1, 0x8 * 0 + 2, + 0x8 * 1, 0x8 * 1 + 1, 0x8 * 1 + 2, + 0x8 * 2, 0x8 * 2 + 1, 0x8 * 2 + 2, + 0x8 * 3, 0x8 * 3 + 1, 0x8 * 3 + 2, + 0x8 * 4, 0x8 * 4 + 1, 0x8 * 4 + 2, + 0x8 * 5, 0x8 * 5 + 1, 0x8 * 5 + 2, + 0x8 * 6, 0x8 * 6 + 1, 0x8 * 6 + 2, + 0x8 * 7, 0x8 * 7 + 1, 0x8 * 7 + 2 + }, + .oobfree = { + { 0x8 * 0 + 3, 5 }, + { 0x8 * 1 + 3, 5 }, + { 0x8 * 2 + 3, 5 }, + { 0x8 * 3 + 3, 5 }, + { 0x8 * 4 + 3, 5 }, + { 0x8 * 5 + 3, 5 }, + { 0x8 * 6 + 3, 5 }, + { 0x8 * 7 + 3, 5 }, + } +}; +#endif + /* * Data structures for bf5xx nand flash controller driver */ @@ -712,6 +747,11 @@ static int bf5xx_nand_probe(struct platform_device *pdev) /* setup hardware ECC data struct */ if (hardware_ecc) { +#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC + chip->badblock_pattern = &bootrom_bbt; + chip->ecc.layout = &bootrom_ecclayout; +#endif + if (plat->page_size == NFC_PG_SIZE_256) { chip->ecc.bytes = 3; chip->ecc.size = 256; -- cgit v1.2.3 From 2445af3853928bf3ee7960e09f548a1b07924091 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 30 Jul 2008 12:35:02 -0700 Subject: [MTD] [NAND] Blackfin NFC Driver: add proper devinit/devexit markings to probe/remove functions Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/nand/bf5xx_nand.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 3555f6b3ebe..e259a7b75b2 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -640,7 +640,7 @@ static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info) #endif } -static int bf5xx_nand_remove(struct platform_device *pdev) +static int __devexit bf5xx_nand_remove(struct platform_device *pdev) { struct bf5xx_nand_info *info = to_nand_info(pdev); struct mtd_info *mtd = NULL; @@ -673,7 +673,7 @@ static int bf5xx_nand_remove(struct platform_device *pdev) * it can allocate all necessary resources then calls the * nand layer to look for devices */ -static int bf5xx_nand_probe(struct platform_device *pdev) +static int __devinit bf5xx_nand_probe(struct platform_device *pdev) { struct bf5xx_nand_platform *plat = to_nand_plat(pdev); struct bf5xx_nand_info *info = NULL; @@ -815,7 +815,7 @@ static int bf5xx_nand_resume(struct platform_device *dev) /* driver device registration */ static struct platform_driver bf5xx_nand_driver = { .probe = bf5xx_nand_probe, - .remove = bf5xx_nand_remove, + .remove = __devexit_p(bf5xx_nand_remove), .suspend = bf5xx_nand_suspend, .resume = bf5xx_nand_resume, .driver = { -- cgit v1.2.3 From a0dd20184becf5c90996d9ee0bb69426fe63581a Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 30 Jul 2008 12:35:02 -0700 Subject: [MTD] [NAND] Blackfin NFC Driver: enable Blackfin nand HWECC support by default Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/nand/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index c075b47e11a..02f9cc30d77 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -104,6 +104,7 @@ config MTD_NAND_BF5XX config MTD_NAND_BF5XX_HWECC bool "BF5XX NAND Hardware ECC" + default y depends on MTD_NAND_BF5XX help Enable the use of the BF5XX's internal ECC generator when -- cgit v1.2.3 From 0ee002b041cb45ab3cc5384b86271d41ccf90fe1 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 30 Jul 2008 12:35:03 -0700 Subject: [MTD] [NAND] Blackfin NFC Driver: use standard dev_err() rather than printk() Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/nand/bf5xx_nand.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index e259a7b75b2..6cf7fb86c25 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -684,8 +684,7 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "(%p)\n", pdev); if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) { - printk(KERN_ERR DRV_NAME - ": Requesting Peripherals failed\n"); + dev_err(&pdev->dev, "requesting Peripherals failed\n"); return -EFAULT; } -- cgit v1.2.3 From 4f0ca70e52b67f41287d853f0d572dafa875e485 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 30 Jul 2008 12:35:04 -0700 Subject: [MTD] [NAND] Blackfin NFC Driver: Cleanup the error exit path of bf5xx_nand_probe function Signed-off-by: Bryan Wu Cc: Mike Frysinger Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/nand/bf5xx_nand.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 6cf7fb86c25..9af2a2cc115 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -549,7 +549,6 @@ static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd, /* * System initialization functions */ - static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info) { int ret; @@ -582,6 +581,13 @@ static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info) return 0; } +static void bf5xx_nand_dma_remove(struct bf5xx_nand_info *info) +{ + /* Free NFC DMA channel */ + if (hardware_ecc) + free_dma(CH_NFC); +} + /* * BF5XX NFC hardware initialization * - pin mux setup @@ -658,6 +664,7 @@ static int __devexit bf5xx_nand_remove(struct platform_device *pdev) } peripheral_free_list(bfin_nfc_pin_req); + bf5xx_nand_dma_remove(info); /* free the common resources */ kfree(info); @@ -683,21 +690,21 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "(%p)\n", pdev); + if (!plat) { + dev_err(&pdev->dev, "no platform specific information\n"); + return -EINVAL; + } + if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) { dev_err(&pdev->dev, "requesting Peripherals failed\n"); return -EFAULT; } - if (!plat) { - dev_err(&pdev->dev, "no platform specific information\n"); - goto exit_error; - } - info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) { dev_err(&pdev->dev, "no memory for flash info\n"); err = -ENOMEM; - goto exit_error; + goto out_err_kzalloc; } platform_set_drvdata(pdev, info); @@ -741,8 +748,8 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev) /* initialise the hardware */ err = bf5xx_nand_hw_init(info); - if (err != 0) - goto exit_error; + if (err) + goto out_err_hw_init; /* setup hardware ECC data struct */ if (hardware_ecc) { @@ -772,7 +779,7 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev) /* scan hardware nand chip and setup mtd info data struct */ if (nand_scan(mtd, 1)) { err = -ENXIO; - goto exit_error; + goto out_err_nand_scan; } /* add NAND partition */ @@ -781,11 +788,14 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "initialised ok\n"); return 0; -exit_error: - bf5xx_nand_remove(pdev); +out_err_nand_scan: + bf5xx_nand_dma_remove(info); +out_err_hw_init: + platform_set_drvdata(pdev, NULL); + kfree(info); +out_err_kzalloc: + peripheral_free_list(bfin_nfc_pin_req); - if (err == 0) - err = -EINVAL; return err; } -- cgit v1.2.3 From e4c094a595ba8ea402e6b2153f7bbf6ef039eea0 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 30 Jul 2008 12:35:04 -0700 Subject: [MTD] [NAND] drivers/mtd/nand/nandsim.c: fix printk warnings Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/nand/nandsim.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 5d08514f553..556e8131ecd 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -586,7 +586,8 @@ static int init_nandsim(struct mtd_info *mtd) if (ns->busw == 16) NS_WARN("16-bit flashes support wasn't tested\n"); - printk("flash size: %llu MiB\n", ns->geom.totsz >> 20); + printk("flash size: %llu MiB\n", + (unsigned long long)ns->geom.totsz >> 20); printk("page size: %u bytes\n", ns->geom.pgsz); printk("OOB area size: %u bytes\n", ns->geom.oobsz); printk("sector size: %u KiB\n", ns->geom.secsz >> 10); @@ -595,8 +596,9 @@ static int init_nandsim(struct mtd_info *mtd) printk("bus width: %u\n", ns->busw); printk("bits in sector size: %u\n", ns->geom.secshift); printk("bits in page size: %u\n", ns->geom.pgshift); - printk("bits in OOB size: %u\n", ns->geom.oobshift); - printk("flash size with OOB: %llu KiB\n", ns->geom.totszoob >> 10); + printk("bits in OOB size: %u\n", ns->geom.oobshift); + printk("flash size with OOB: %llu KiB\n", + (unsigned long long)ns->geom.totszoob >> 10); printk("page address bytes: %u\n", ns->geom.pgaddrbytes); printk("sector address bytes: %u\n", ns->geom.secaddrbytes); printk("options: %#x\n", ns->options); -- cgit v1.2.3 From d5686b444ff3f72808d2b3fbd58672a86cdf38e7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 1 Aug 2008 05:00:11 -0400 Subject: [PATCH] switch mtd and dm-table to lookup_bdev() No need to open-code it... Signed-off-by: Al Viro --- drivers/md/dm-table.c | 29 ++++++----------------------- drivers/mtd/mtdsuper.c | 33 +++++++++++---------------------- 2 files changed, 17 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 798e468103b..61f44140923 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -316,29 +316,12 @@ static inline int check_space(struct dm_table *t) */ static int lookup_device(const char *path, dev_t *dev) { - int r; - struct nameidata nd; - struct inode *inode; - - if ((r = path_lookup(path, LOOKUP_FOLLOW, &nd))) - return r; - - inode = nd.path.dentry->d_inode; - if (!inode) { - r = -ENOENT; - goto out; - } - - if (!S_ISBLK(inode->i_mode)) { - r = -ENOTBLK; - goto out; - } - - *dev = inode->i_rdev; - - out: - path_put(&nd.path); - return r; + struct block_device *bdev = lookup_bdev(path); + if (IS_ERR(bdev)) + return PTR_ERR(bdev); + *dev = bdev->bd_dev; + bdput(bdev); + return 0; } /* diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c index 28cc6787a80..9b6af7e74a6 100644 --- a/drivers/mtd/mtdsuper.c +++ b/drivers/mtd/mtdsuper.c @@ -125,7 +125,7 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, int (*fill_super)(struct super_block *, void *, int), struct vfsmount *mnt) { - struct nameidata nd; + struct block_device *bdev; int mtdnr, ret; if (!dev_name) @@ -181,29 +181,20 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, /* try the old way - the hack where we allowed users to mount * /dev/mtdblock$(n) but didn't actually _use_ the blockdev */ - ret = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); - - DEBUG(1, "MTDSB: path_lookup() returned %d, inode %p\n", - ret, nd.path.dentry ? nd.path.dentry->d_inode : NULL); - - if (ret) + bdev = lookup_bdev(dev_name); + if (IS_ERR(bdev)) { + ret = PTR_ERR(bdev); + DEBUG(1, "MTDSB: lookup_bdev() returned %d\n", ret); return ret; - - ret = -EINVAL; - - if (!S_ISBLK(nd.path.dentry->d_inode->i_mode)) - goto out; - - if (nd.path.mnt->mnt_flags & MNT_NODEV) { - ret = -EACCES; - goto out; } + DEBUG(1, "MTDSB: lookup_bdev() returned 0\n"); - if (imajor(nd.path.dentry->d_inode) != MTD_BLOCK_MAJOR) + ret = -EINVAL; + if (MAJOR(bdev->bd_dev) != MTD_BLOCK_MAJOR) goto not_an_MTD_device; - mtdnr = iminor(nd.path.dentry->d_inode); - path_put(&nd.path); + mtdnr = MINOR(bdev->bd_dev); + bdput(bdev); return get_sb_mtd_nr(fs_type, flags, dev_name, data, mtdnr, fill_super, mnt); @@ -213,10 +204,8 @@ not_an_MTD_device: printk(KERN_NOTICE "MTD: Attempt to mount non-MTD device \"%s\"\n", dev_name); -out: - path_put(&nd.path); + bdput(bdev); return ret; - } EXPORT_SYMBOL_GPL(get_sb_mtd); -- cgit v1.2.3 From 4a3cba32cb514168bb2516c045b178e6660421d1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 29 Jul 2008 00:11:16 +0200 Subject: sdhci: handle bug in JMB38x for sizes < 4 bytes Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci-pci.c | 3 ++- drivers/mmc/host/sdhci.c | 9 +++++++++ drivers/mmc/host/sdhci.h | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index deb607c52c0..fcb14c2346c 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -143,7 +143,8 @@ static int jmicron_probe(struct sdhci_pci_chip *chip) chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_32BIT_DMA_SIZE | SDHCI_QUIRK_32BIT_ADMA_SIZE | - SDHCI_QUIRK_RESET_AFTER_REQUEST; + SDHCI_QUIRK_RESET_AFTER_REQUEST | + SDHCI_QUIRK_BROKEN_SMALL_PIO; } /* diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 5f95e10229b..be09739f692 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -278,6 +278,15 @@ static void sdhci_transfer_pio(struct sdhci_host *host) else mask = SDHCI_SPACE_AVAILABLE; + /* + * Some controllers (JMicron JMB38x) mess up the buffer bits + * for transfers < 4 bytes. As long as it is just one block, + * we can ignore the bits. + */ + if ((host->quirks & SDHCI_QUIRK_BROKEN_SMALL_PIO) && + (host->data->blocks == 1)) + mask = ~0; + while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) { if (host->data->flags & MMC_DATA_READ) sdhci_read_block_pio(host); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index e354faee5df..197d4a05f4a 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -206,6 +206,8 @@ struct sdhci_host { #define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<11) /* Controller provides an incorrect timeout value for transfers */ #define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12) +/* Controller has an issue with buffer bits for small transfers */ +#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13) int irq; /* Device IRQ */ void __iomem * ioaddr; /* Mapped address */ -- cgit v1.2.3 From ebd6d357848edb8709dd9bed4b93834d1b4d7044 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 29 Jul 2008 00:45:51 +0200 Subject: sdhci: disable DMA for req, not completely The wrong flag was manipulated when an invalid sg list was given, turning off DMA on the next (and all subsequent) request instead of the current one. Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index be09739f692..9191aaf2e52 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -654,7 +654,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) * us an invalid request. */ WARN_ON(1); - host->flags &= ~SDHCI_USE_DMA; + host->flags &= ~SDHCI_REQ_USE_DMA; } else { writel(host->adma_addr, host->ioaddr + SDHCI_ADMA_ADDRESS); @@ -673,7 +673,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) * us an invalid request. */ WARN_ON(1); - host->flags &= ~SDHCI_USE_DMA; + host->flags &= ~SDHCI_REQ_USE_DMA; } else { WARN_ON(sg_cnt != 1); writel(sg_dma_address(data->sg), -- cgit v1.2.3 From 980167b7fb20fb181766218b4771fc7420a7bbb4 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 29 Jul 2008 00:53:20 +0200 Subject: sdhci: check correct return value Fix a copy-and-paste error. Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 9191aaf2e52..e3a8133560a 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -448,7 +448,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, host->adma_addr = dma_map_single(mmc_dev(host->mmc), host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE); - if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr)) + if (dma_mapping_error(mmc_dev(host->mmc), host->adma_addr)) goto unmap_entries; BUG_ON(host->adma_addr & 0x3); -- cgit v1.2.3 From b7ac2cf1cdf346b34cbc2104d386a9d29d12aa4c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 29 Jul 2008 01:05:22 +0200 Subject: mmc_test: Revert "mmc_test: test oversized sg lists" This reverts commit 48b5352ea1891455eb8e824cf7d92f66931a090f. Oversized sg lists are not allowed anymore, and the core even checks for them in debug mode, so this test is entirely incorrect. Signed-off-by: Pierre Ossman --- drivers/mmc/card/mmc_test.c | 85 ++------------------------------------------- 1 file changed, 3 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index a067fe43630..f26b01d811a 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -388,16 +388,14 @@ static int mmc_test_transfer(struct mmc_test_card *test, int ret, i; unsigned long flags; - BUG_ON(blocks * blksz > BUFFER_SIZE); - if (write) { for (i = 0;i < blocks * blksz;i++) test->scratch[i] = i; } else { - memset(test->scratch, 0, blocks * blksz); + memset(test->scratch, 0, BUFFER_SIZE); } local_irq_save(flags); - sg_copy_from_buffer(sg, sg_len, test->scratch, blocks * blksz); + sg_copy_from_buffer(sg, sg_len, test->scratch, BUFFER_SIZE); local_irq_restore(flags); ret = mmc_test_set_blksize(test, blksz); @@ -444,7 +442,7 @@ static int mmc_test_transfer(struct mmc_test_card *test, } } else { local_irq_save(flags); - sg_copy_to_buffer(sg, sg_len, test->scratch, blocks * blksz); + sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE); local_irq_restore(flags); for (i = 0;i < blocks * blksz;i++) { if (test->scratch[i] != (u8)i) @@ -805,69 +803,6 @@ static int mmc_test_multi_xfersize_read(struct mmc_test_card *test) return 0; } -static int mmc_test_bigsg_write(struct mmc_test_card *test) -{ - int ret; - unsigned int size; - struct scatterlist sg; - - if (test->card->host->max_blk_count == 1) - return RESULT_UNSUP_HOST; - - size = PAGE_SIZE * 2; - size = min(size, test->card->host->max_req_size); - size = min(size, test->card->host->max_seg_size); - size = min(size, test->card->host->max_blk_count * 512); - - memset(test->buffer, 0, BUFFER_SIZE); - - if (size < 1024) - return RESULT_UNSUP_HOST; - - sg_init_table(&sg, 1); - sg_init_one(&sg, test->buffer, BUFFER_SIZE); - - ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1); - if (ret) - return ret; - - return 0; -} - -static int mmc_test_bigsg_read(struct mmc_test_card *test) -{ - int ret, i; - unsigned int size; - struct scatterlist sg; - - if (test->card->host->max_blk_count == 1) - return RESULT_UNSUP_HOST; - - size = PAGE_SIZE * 2; - size = min(size, test->card->host->max_req_size); - size = min(size, test->card->host->max_seg_size); - size = min(size, test->card->host->max_blk_count * 512); - - if (size < 1024) - return RESULT_UNSUP_HOST; - - memset(test->buffer, 0xCD, BUFFER_SIZE); - - sg_init_table(&sg, 1); - sg_init_one(&sg, test->buffer, BUFFER_SIZE); - ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0); - if (ret) - return ret; - - /* mmc_test_transfer() doesn't check for read overflows */ - for (i = size;i < BUFFER_SIZE;i++) { - if (test->buffer[i] != 0xCD) - return RESULT_FAIL; - } - - return 0; -} - #ifdef CONFIG_HIGHMEM static int mmc_test_write_high(struct mmc_test_card *test) @@ -1071,20 +1006,6 @@ static const struct mmc_test_case mmc_test_cases[] = { .run = mmc_test_multi_xfersize_read, }, - { - .name = "Over-sized SG list write", - .prepare = mmc_test_prepare_write, - .run = mmc_test_bigsg_write, - .cleanup = mmc_test_cleanup, - }, - - { - .name = "Over-sized SG list read", - .prepare = mmc_test_prepare_read, - .run = mmc_test_bigsg_read, - .cleanup = mmc_test_cleanup, - }, - #ifdef CONFIG_HIGHMEM { -- cgit v1.2.3 From a84756c5735f28bf000617f18734a9e94426386a Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 29 Jul 2008 01:09:37 +0200 Subject: mmc: properly iterate over sg list in debug check Signed-off-by: Pierre Ossman --- drivers/mmc/core/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 3ee5b8c3b5c..044d84eeed7 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -121,6 +121,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) { #ifdef CONFIG_MMC_DEBUG unsigned int i, sz; + struct scatterlist *sg; #endif pr_debug("%s: starting CMD%u arg %08x flags %08x\n", @@ -156,8 +157,8 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) #ifdef CONFIG_MMC_DEBUG sz = 0; - for (i = 0;i < mrq->data->sg_len;i++) - sz += mrq->data->sg[i].length; + for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i) + sz += sg->length; BUG_ON(sz != mrq->data->blocks * mrq->data->blksz); #endif -- cgit v1.2.3 From b41e9c7b8e14ea57aa0fc05fd63a0de0e935d58d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 29 Jul 2008 01:23:24 +0200 Subject: mmc_block: use proper sg iterators Signed-off-by: Pierre Ossman --- drivers/mmc/card/block.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 66e5a5487c2..86dbb366415 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -213,7 +213,8 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) struct mmc_blk_data *md = mq->data; struct mmc_card *card = md->queue.card; struct mmc_blk_request brq; - int ret = 1, sg_pos, data_size; + int ret = 1, data_size, i; + struct scatterlist *sg; mmc_claim_host(card->host); @@ -267,18 +268,22 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) mmc_queue_bounce_pre(mq); + /* + * Adjust the sg list so it is the same size as the + * request. + */ if (brq.data.blocks != (req->nr_sectors >> (md->block_bits - 9))) { data_size = brq.data.blocks * brq.data.blksz; - for (sg_pos = 0; sg_pos < brq.data.sg_len; sg_pos++) { - data_size -= mq->sg[sg_pos].length; + for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) { + data_size -= sg->length; if (data_size <= 0) { - mq->sg[sg_pos].length += data_size; - sg_pos++; + sg->length += data_size; + i++; break; } } - brq.data.sg_len = sg_pos; + brq.data.sg_len = i; } mmc_wait_for_req(card->host, &brq.mrq); -- cgit v1.2.3 From e491d230fd398bb730e3c2dd734c5447463b9d38 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Tue, 29 Jul 2008 10:10:49 +0200 Subject: au1xmmc: raise segment size limit. Raise the DMA block size limit from 2048 bytes to the maximum supported by the DMA controllers on the chip (64KB on Au1100, 4MB on Au1200). This gives a very small performance boost and apparently fixes an oops when MMC-DMA and network traffic are active at the same time. Signed-off-by: Manuel Lauss Signed-off-by: Pierre Ossman --- drivers/mmc/host/au1xmmc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 99b20917cc0..d3f55615c09 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -61,7 +61,13 @@ /* Hardware definitions */ #define AU1XMMC_DESCRIPTOR_COUNT 1 -#define AU1XMMC_DESCRIPTOR_SIZE 2048 + +/* max DMA seg size: 64KB on Au1100, 4MB on Au1200 */ +#ifdef CONFIG_SOC_AU1100 +#define AU1XMMC_DESCRIPTOR_SIZE 0x0000ffff +#else /* Au1200 */ +#define AU1XMMC_DESCRIPTOR_SIZE 0x003fffff +#endif #define AU1XMMC_OCR (MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | \ MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | \ -- cgit v1.2.3 From 93769f58078e2a066b56217cae1e343ac5a6b78c Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 1 Aug 2008 20:32:31 +0200 Subject: md: the bitmap code needs to use blk_plug_device_unlocked() It doesn't hold the queue lock, so it's both racey on the queue flags and thus spews a warning. Signed-off-by: Jens Axboe --- drivers/md/bitmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 621a272a2c7..7e65bad522c 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1234,7 +1234,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect case 0: bitmap_file_set_bit(bitmap, offset); bitmap_count_page(bitmap,offset, 1); - blk_plug_device(bitmap->mddev->queue); + blk_plug_device_unlocked(bitmap->mddev->queue); /* fall through */ case 1: *bmc = 2; -- cgit v1.2.3 From 3b0de7b364c8b8a975f201fdae2fb394c876eb56 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 1 Aug 2008 14:19:08 -0500 Subject: add dependency of CONFIG_SGI_XP upon CONFIG_NET Add a dependency of CONFIG_SGI_XP upon CONFIG_NET to Kconfig. Signed-off-by: Dean Nelson Signed-off-by: Linus Torvalds --- drivers/misc/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index fa50e9ede0e..0db06f1f4b5 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -426,6 +426,7 @@ config ENCLOSURE_SERVICES config SGI_XP tristate "Support communication between SGI SSIs" + depends on NET depends on IA64_GENERIC || IA64_SGI_SN2 || IA64_SGI_UV || (X86_64 && SMP) select IA64_UNCACHED_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 select GENERIC_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 -- cgit v1.2.3 From 46bd58eab21650fe820e4e3a27a6a134892cc2eb Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 1 Aug 2008 09:55:26 -0500 Subject: add reverse dependency of CONFIG_SGI_XP upon CONFIG_SGI_GRU Add a reverse dependency of CONFIG_SGI_XP upon CONFIG_SGI_GRU to Kconfig. Signed-off-by: Dean Nelson Signed-off-by: Linus Torvalds --- drivers/misc/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 0db06f1f4b5..82af385460e 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -430,6 +430,7 @@ config SGI_XP depends on IA64_GENERIC || IA64_SGI_SN2 || IA64_SGI_UV || (X86_64 && SMP) select IA64_UNCACHED_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 select GENERIC_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 + select SGI_GRU if IA64_GENERIC || IA64_SGI_UV || (X86_64 && SMP) ---help--- An SGI machine can be divided into multiple Single System Images which act independently of each other and have -- cgit v1.2.3 From 0bacdf303f72a3ed34252934114bc04e79222687 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Wed, 30 Jul 2008 13:18:59 +0300 Subject: ath5k: Update register list * Update list of registers * Use updated register macros inside hw.c, initvals.c and debug.c Changes-licensed-under: ISC Signed-off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/debug.c | 2 +- drivers/net/wireless/ath5k/hw.c | 43 +- drivers/net/wireless/ath5k/initvals.c | 4 +- drivers/net/wireless/ath5k/reg.h | 934 +++++++++++++++++++++++++--------- 4 files changed, 720 insertions(+), 263 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/debug.c b/drivers/net/wireless/ath5k/debug.c index 41d5fa34b54..6fa6c8e04ff 100644 --- a/drivers/net/wireless/ath5k/debug.c +++ b/drivers/net/wireless/ath5k/debug.c @@ -129,7 +129,7 @@ static struct reg regs[] = { REG_STRUCT_INIT(AR5K_CPC1), REG_STRUCT_INIT(AR5K_CPC2), REG_STRUCT_INIT(AR5K_CPC3), - REG_STRUCT_INIT(AR5K_CPCORN), + REG_STRUCT_INIT(AR5K_CPCOVF), REG_STRUCT_INIT(AR5K_RESET_CTL), REG_STRUCT_INIT(AR5K_SLEEP_CTL), REG_STRUCT_INIT(AR5K_INTPEND), diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index 7ca87a55731..42ef41ed5d1 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c @@ -843,27 +843,26 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, * Write some more initial register settings */ if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, 0x0002a002, AR5K_PHY(11)); + ath5k_hw_reg_write(ah, 0x0002a002, 0x982c); if (channel->hw_value == CHANNEL_G) if (ah->ah_mac_srev < AR5K_SREV_VER_AR2413) ath5k_hw_reg_write(ah, 0x00f80d80, - AR5K_PHY(83)); + 0x994c); else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2424) ath5k_hw_reg_write(ah, 0x00380140, - AR5K_PHY(83)); + 0x994c); else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2425) ath5k_hw_reg_write(ah, 0x00fc0ec0, - AR5K_PHY(83)); + 0x994c); else /* 2425 */ ath5k_hw_reg_write(ah, 0x00fc0fc0, - AR5K_PHY(83)); + 0x994c); else - ath5k_hw_reg_write(ah, 0x00000000, - AR5K_PHY(83)); + ath5k_hw_reg_write(ah, 0x00000000, 0x994c); ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); - ath5k_hw_reg_write(ah, 0x0000000f, 0x8060); + ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK); ath5k_hw_reg_write(ah, 0x00000000, 0xa254); ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL); } @@ -935,7 +934,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, return ret; /* Set antenna mode */ - AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x44), + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_ANT_CTL, ah->ah_antenna[ee_mode][0], 0xfffffc06); /* @@ -965,15 +964,15 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, ath5k_hw_reg_write(ah, AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]), - AR5K_PHY(0x5a)); + AR5K_PHY_NFTHRES); - AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x11), + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_SETTLING, (ee->ee_switch_settling[ee_mode] << 7) & 0x3f80, 0xffffc07f); - AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x12), + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN, (ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000, 0xfffc0fff); - AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x14), + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE, (ee->ee_adc_desired_size[ee_mode] & 0x00ff) | ((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00), 0xffff0000); @@ -982,13 +981,13 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, (ee->ee_tx_end2xpa_disable[ee_mode] << 24) | (ee->ee_tx_end2xpa_disable[ee_mode] << 16) | (ee->ee_tx_frm2xpa_enable[ee_mode] << 8) | - (ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY(0x0d)); + (ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4); - AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x0a), + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_RF_CTL3, ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff); - AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x19), + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_NF, (ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff); - AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x49), 4, 0xffffff01); + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_OFDM_SELFCORR, 4, 0xffffff01); AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE | @@ -3363,11 +3362,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) ath5k_hw_reg_write(ah, ah->ah_turbo ? AR5K_INIT_PROTO_TIME_CNTRL_TURBO : AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1); - /* Set PHY register 0x9844 (??) */ + /* Set AR5K_PHY_SETTLING */ ath5k_hw_reg_write(ah, ah->ah_turbo ? - (ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x38 : - (ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x1C, - AR5K_PHY(17)); + (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F) + | 0x38 : + (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F) + | 0x1C, + AR5K_PHY_SETTLING); /* Set Frame Control Register */ ath5k_hw_reg_write(ah, ah->ah_turbo ? (AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE | diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath5k/initvals.c index 04c84e9da89..2806b21bf90 100644 --- a/drivers/net/wireless/ath5k/initvals.c +++ b/drivers/net/wireless/ath5k/initvals.c @@ -489,7 +489,7 @@ static const struct ath5k_ini ar5212_ini[] = { { AR5K_QUEUE_TXDP(9), 0x00000000 }, { AR5K_DCU_FP, 0x00000000 }, { AR5K_DCU_TXP, 0x00000000 }, - { AR5K_DCU_TX_FILTER, 0x00000000 }, + { AR5K_DCU_TX_FILTER_0_BASE, 0x00000000 }, /* Unknown table */ { 0x1078, 0x00000000 }, { 0x10b8, 0x00000000 }, @@ -679,7 +679,7 @@ static const struct ath5k_ini ar5212_ini[] = { { AR5K_PHY(645), 0x00106c10 }, { AR5K_PHY(646), 0x009c4060 }, { AR5K_PHY(647), 0x1483800a }, - /* { AR5K_PHY(648), 0x018830c6 },*/ /* 2413 */ + /* { AR5K_PHY(648), 0x018830c6 },*/ /* 2413/2425 */ { AR5K_PHY(648), 0x01831061 }, { AR5K_PHY(649), 0x00000400 }, /*{ AR5K_PHY(650), 0x000001b5 },*/ diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h index 30629b3e37c..7562bf173d3 100644 --- a/drivers/net/wireless/ath5k/reg.h +++ b/drivers/net/wireless/ath5k/reg.h @@ -53,7 +53,7 @@ #define AR5K_CR_TXD0 0x00000008 /* TX Disable for queue 0 on 5210 */ #define AR5K_CR_TXD1 0x00000010 /* TX Disable for queue 1 on 5210 */ #define AR5K_CR_RXD 0x00000020 /* RX Disable */ -#define AR5K_CR_SWI 0x00000040 +#define AR5K_CR_SWI 0x00000040 /* Software Interrupt */ /* * RX Descriptor Pointer register @@ -65,19 +65,19 @@ */ #define AR5K_CFG 0x0014 /* Register Address */ #define AR5K_CFG_SWTD 0x00000001 /* Byte-swap TX descriptor (for big endian archs) */ -#define AR5K_CFG_SWTB 0x00000002 /* Byte-swap TX buffer (?) */ +#define AR5K_CFG_SWTB 0x00000002 /* Byte-swap TX buffer */ #define AR5K_CFG_SWRD 0x00000004 /* Byte-swap RX descriptor */ -#define AR5K_CFG_SWRB 0x00000008 /* Byte-swap RX buffer (?) */ -#define AR5K_CFG_SWRG 0x00000010 /* Byte-swap Register values (?) */ -#define AR5K_CFG_ADHOC 0x00000020 /* [5211+] */ +#define AR5K_CFG_SWRB 0x00000008 /* Byte-swap RX buffer */ +#define AR5K_CFG_SWRG 0x00000010 /* Byte-swap Register access */ +#define AR5K_CFG_ADHOC 0x00000020 /* AP/Adhoc indication [5211+] */ #define AR5K_CFG_PHY_OK 0x00000100 /* [5211+] */ #define AR5K_CFG_EEBS 0x00000200 /* EEPROM is busy */ -#define AR5K_CFG_CLKGD 0x00000400 /* Clock gated (?) */ +#define AR5K_CFG_CLKGD 0x00000400 /* Clock gated (Disable dynamic clock) */ #define AR5K_CFG_TXCNT 0x00007800 /* Tx frame count (?) [5210] */ #define AR5K_CFG_TXCNT_S 11 #define AR5K_CFG_TXFSTAT 0x00008000 /* Tx frame status (?) [5210] */ #define AR5K_CFG_TXFSTRT 0x00010000 /* [5210] */ -#define AR5K_CFG_PCI_THRES 0x00060000 /* [5211+] */ +#define AR5K_CFG_PCI_THRES 0x00060000 /* PCI Master req q threshold [5211+] */ #define AR5K_CFG_PCI_THRES_S 17 /* @@ -162,35 +162,40 @@ /* * Transmit configuration register */ -#define AR5K_TXCFG 0x0030 /* Register Address */ -#define AR5K_TXCFG_SDMAMR 0x00000007 /* DMA size */ -#define AR5K_TXCFG_SDMAMR_S 0 -#define AR5K_TXCFG_B_MODE 0x00000008 /* Set b mode for 5111 (enable 2111) */ -#define AR5K_TXCFG_TXFSTP 0x00000008 /* TX DMA full Stop [5210] */ -#define AR5K_TXCFG_TXFULL 0x000003f0 /* TX Triger level mask */ -#define AR5K_TXCFG_TXFULL_S 4 -#define AR5K_TXCFG_TXFULL_0B 0x00000000 -#define AR5K_TXCFG_TXFULL_64B 0x00000010 -#define AR5K_TXCFG_TXFULL_128B 0x00000020 -#define AR5K_TXCFG_TXFULL_192B 0x00000030 -#define AR5K_TXCFG_TXFULL_256B 0x00000040 -#define AR5K_TXCFG_TXCONT_EN 0x00000080 -#define AR5K_TXCFG_DMASIZE 0x00000100 /* Flag for passing DMA size [5210] */ -#define AR5K_TXCFG_JUMBO_TXE 0x00000400 /* Enable jumbo frames transmition (?) [5211+] */ -#define AR5K_TXCFG_RTSRND 0x00001000 /* [5211+] */ -#define AR5K_TXCFG_FRMPAD_DIS 0x00002000 /* [5211+] */ -#define AR5K_TXCFG_RDY_DIS 0x00004000 /* [5211+] */ +#define AR5K_TXCFG 0x0030 /* Register Address */ +#define AR5K_TXCFG_SDMAMR 0x00000007 /* DMA size (read) */ +#define AR5K_TXCFG_SDMAMR_S 0 +#define AR5K_TXCFG_B_MODE 0x00000008 /* Set b mode for 5111 (enable 2111) */ +#define AR5K_TXCFG_TXFSTP 0x00000008 /* TX DMA full Stop [5210] */ +#define AR5K_TXCFG_TXFULL 0x000003f0 /* TX Triger level mask */ +#define AR5K_TXCFG_TXFULL_S 4 +#define AR5K_TXCFG_TXFULL_0B 0x00000000 +#define AR5K_TXCFG_TXFULL_64B 0x00000010 +#define AR5K_TXCFG_TXFULL_128B 0x00000020 +#define AR5K_TXCFG_TXFULL_192B 0x00000030 +#define AR5K_TXCFG_TXFULL_256B 0x00000040 +#define AR5K_TXCFG_TXCONT_EN 0x00000080 +#define AR5K_TXCFG_DMASIZE 0x00000100 /* Flag for passing DMA size [5210] */ +#define AR5K_TXCFG_JUMBO_DESC_EN 0x00000400 /* Enable jumbo tx descriptors [5211+] */ +#define AR5K_TXCFG_ADHOC_BCN_ATIM 0x00000800 /* Adhoc Beacon ATIM Policy */ +#define AR5K_TXCFG_ATIM_WINDOW_DEF_DIS 0x00001000 /* Disable ATIM window defer [5211+] */ +#define AR5K_TXCFG_RTSRND 0x00001000 /* [5211+] */ +#define AR5K_TXCFG_FRMPAD_DIS 0x00002000 /* [5211+] */ +#define AR5K_TXCFG_RDY_CBR_DIS 0x00004000 /* Ready time CBR disable [5211+] */ +#define AR5K_TXCFG_JUMBO_FRM_MODE 0x00008000 /* Jumbo frame mode [5211+] */ +#define AR5K_TXCFG_DCU_CACHING_DIS 0x00010000 /* Disable DCU caching */ /* * Receive configuration register */ #define AR5K_RXCFG 0x0034 /* Register Address */ -#define AR5K_RXCFG_SDMAMW 0x00000007 /* DMA size */ +#define AR5K_RXCFG_SDMAMW 0x00000007 /* DMA size (write) */ #define AR5K_RXCFG_SDMAMW_S 0 -#define AR5K_RXCFG_DEF_ANTENNA 0x00000008 /* Default antenna */ -#define AR5K_RXCFG_ZLFDMA 0x00000010 /* Zero-length DMA */ -#define AR5K_RXCFG_JUMBO_RXE 0x00000020 /* Enable jumbo frames reception (?) [5211+] */ -#define AR5K_RXCFG_JUMBO_WRAP 0x00000040 /* Wrap jumbo frames (?) [5211+] */ +#define AR5K_RXCFG_ZLFDMA 0x00000008 /* Enable Zero-length frame DMA */ +#define AR5K_RXCFG_DEF_ANTENNA 0x00000010 /* Default antenna (?) */ +#define AR5K_RXCFG_JUMBO_RXE 0x00000020 /* Enable jumbo rx descriptors [5211+] */ +#define AR5K_RXCFG_JUMBO_WRAP 0x00000040 /* Wrap jumbo frames [5211+] */ +#define AR5K_RXCFG_SLE_ENTRY 0x00000080 /* Sleep entry policy */ /* * Receive jumbo descriptor last address register @@ -202,35 +207,35 @@ * MIB control register */ #define AR5K_MIBC 0x0040 /* Register Address */ -#define AR5K_MIBC_COW 0x00000001 -#define AR5K_MIBC_FMC 0x00000002 /* Freeze Mib Counters (?) */ -#define AR5K_MIBC_CMC 0x00000004 /* Clean Mib Counters (?) */ -#define AR5K_MIBC_MCS 0x00000008 +#define AR5K_MIBC_COW 0x00000001 /* Warn test indicator */ +#define AR5K_MIBC_FMC 0x00000002 /* Freeze MIB Counters */ +#define AR5K_MIBC_CMC 0x00000004 /* Clean MIB Counters */ +#define AR5K_MIBC_MCS 0x00000008 /* MIB counter strobe */ /* * Timeout prescale register */ #define AR5K_TOPS 0x0044 -#define AR5K_TOPS_M 0x0000ffff /* [5211+] (?) */ +#define AR5K_TOPS_M 0x0000ffff /* * Receive timeout register (no frame received) */ #define AR5K_RXNOFRM 0x0048 -#define AR5K_RXNOFRM_M 0x000003ff /* [5211+] (?) */ +#define AR5K_RXNOFRM_M 0x000003ff /* * Transmit timeout register (no frame sent) */ #define AR5K_TXNOFRM 0x004c -#define AR5K_TXNOFRM_M 0x000003ff /* [5211+] (?) */ -#define AR5K_TXNOFRM_QCU 0x000ffc00 /* [5211+] (?) */ +#define AR5K_TXNOFRM_M 0x000003ff +#define AR5K_TXNOFRM_QCU 0x000ffc00 /* * Receive frame gap timeout register */ #define AR5K_RPGTO 0x0050 -#define AR5K_RPGTO_M 0x000003ff /* [5211+] (?) */ +#define AR5K_RPGTO_M 0x000003ff /* * Receive frame count limit register @@ -241,6 +246,7 @@ /* * Misc settings register + * (reserved0-3) */ #define AR5K_MISC 0x0058 /* Register Address */ #define AR5K_MISC_DMA_OBS_M 0x000001e0 @@ -256,6 +262,7 @@ /* * QCU/DCU clock gating register (5311) + * (reserved4-5) */ #define AR5K_QCUDCU_CLKGT 0x005c /* Register Address (?) */ #define AR5K_QCUDCU_CLKGT_QCU 0x0000ffff /* Mask for QCU clock */ @@ -284,18 +291,18 @@ #define AR5K_ISR_TXEOL 0x00000400 /* Empty TX descriptor */ #define AR5K_ISR_TXURN 0x00000800 /* Transmit FIFO underrun */ #define AR5K_ISR_MIB 0x00001000 /* Update MIB counters */ -#define AR5K_ISR_SWI 0x00002000 /* Software interrupt (?) */ +#define AR5K_ISR_SWI 0x00002000 /* Software interrupt */ #define AR5K_ISR_RXPHY 0x00004000 /* PHY error */ -#define AR5K_ISR_RXKCM 0x00008000 +#define AR5K_ISR_RXKCM 0x00008000 /* RX Key cache miss */ #define AR5K_ISR_SWBA 0x00010000 /* Software beacon alert */ #define AR5K_ISR_BRSSI 0x00020000 #define AR5K_ISR_BMISS 0x00040000 /* Beacon missed */ #define AR5K_ISR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */ #define AR5K_ISR_BNR 0x00100000 /* Beacon not ready [5211+] */ -#define AR5K_ISR_MCABT 0x00100000 /* [5210] */ -#define AR5K_ISR_RXCHIRP 0x00200000 /* [5212+] */ -#define AR5K_ISR_SSERR 0x00200000 /* [5210] */ -#define AR5K_ISR_DPERR 0x00400000 /* [5210] */ +#define AR5K_ISR_MCABT 0x00100000 /* Master Cycle Abort [5210] */ +#define AR5K_ISR_RXCHIRP 0x00200000 /* CHIRP Received [5212+] */ +#define AR5K_ISR_SSERR 0x00200000 /* Signaled System Error [5210] */ +#define AR5K_ISR_DPERR 0x00400000 /* Det par Error (?) [5210] */ #define AR5K_ISR_TIM 0x00800000 /* [5210] */ #define AR5K_ISR_BCNMISC 0x00800000 /* [5212+] */ #define AR5K_ISR_GPIO 0x01000000 /* GPIO (rf kill)*/ @@ -320,14 +327,14 @@ #define AR5K_SISR2 0x008c /* Register Address [5211+] */ #define AR5K_SISR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */ -#define AR5K_SISR2_MCABT 0x00100000 -#define AR5K_SISR2_SSERR 0x00200000 -#define AR5K_SISR2_DPERR 0x00400000 +#define AR5K_SISR2_MCABT 0x00100000 /* Master Cycle Abort */ +#define AR5K_SISR2_SSERR 0x00200000 /* Signaled System Error */ +#define AR5K_SISR2_DPERR 0x00400000 /* Det par Error (?) */ #define AR5K_SISR2_TIM 0x01000000 /* [5212+] */ #define AR5K_SISR2_CAB_END 0x02000000 /* [5212+] */ -#define AR5K_SISR2_DTIM_SYNC 0x04000000 /* [5212+] */ -#define AR5K_SISR2_BCN_TIMEOUT 0x08000000 /* [5212+] */ -#define AR5K_SISR2_CAB_TIMEOUT 0x10000000 /* [5212+] */ +#define AR5K_SISR2_DTIM_SYNC 0x04000000 /* DTIM sync lost [5212+] */ +#define AR5K_SISR2_BCN_TIMEOUT 0x08000000 /* Beacon Timeout [5212+] */ +#define AR5K_SISR2_CAB_TIMEOUT 0x10000000 /* CAB Timeout [5212+] */ #define AR5K_SISR2_DTIM 0x20000000 /* [5212+] */ #define AR5K_SISR3 0x0090 /* Register Address [5211+] */ @@ -368,18 +375,18 @@ #define AR5K_IMR_TXEOL 0x00000400 /* Empty TX descriptor*/ #define AR5K_IMR_TXURN 0x00000800 /* Transmit FIFO underrun*/ #define AR5K_IMR_MIB 0x00001000 /* Update MIB counters*/ -#define AR5K_IMR_SWI 0x00002000 +#define AR5K_IMR_SWI 0x00002000 /* Software interrupt */ #define AR5K_IMR_RXPHY 0x00004000 /* PHY error*/ -#define AR5K_IMR_RXKCM 0x00008000 +#define AR5K_IMR_RXKCM 0x00008000 /* RX Key cache miss */ #define AR5K_IMR_SWBA 0x00010000 /* Software beacon alert*/ #define AR5K_IMR_BRSSI 0x00020000 #define AR5K_IMR_BMISS 0x00040000 /* Beacon missed*/ #define AR5K_IMR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */ #define AR5K_IMR_BNR 0x00100000 /* Beacon not ready [5211+] */ -#define AR5K_IMR_MCABT 0x00100000 /* [5210] */ -#define AR5K_IMR_RXCHIRP 0x00200000 /* [5212+]*/ -#define AR5K_IMR_SSERR 0x00200000 /* [5210] */ -#define AR5K_IMR_DPERR 0x00400000 /* [5210] */ +#define AR5K_IMR_MCABT 0x00100000 /* Master Cycle Abort [5210] */ +#define AR5K_IMR_RXCHIRP 0x00200000 /* CHIRP Received [5212+]*/ +#define AR5K_IMR_SSERR 0x00200000 /* Signaled System Error [5210] */ +#define AR5K_IMR_DPERR 0x00400000 /* Det par Error (?) [5210] */ #define AR5K_IMR_TIM 0x00800000 /* [5211+] */ #define AR5K_IMR_BCNMISC 0x00800000 /* [5212+] */ #define AR5K_IMR_GPIO 0x01000000 /* GPIO (rf kill)*/ @@ -405,14 +412,14 @@ #define AR5K_SIMR2 0x00ac /* Register Address [5211+] */ #define AR5K_SIMR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */ #define AR5K_SIMR2_QCU_TXURN_S 0 -#define AR5K_SIMR2_MCABT 0x00100000 -#define AR5K_SIMR2_SSERR 0x00200000 -#define AR5K_SIMR2_DPERR 0x00400000 +#define AR5K_SIMR2_MCABT 0x00100000 /* Master Cycle Abort */ +#define AR5K_SIMR2_SSERR 0x00200000 /* Signaled System Error */ +#define AR5K_SIMR2_DPERR 0x00400000 /* Det par Error (?) */ #define AR5K_SIMR2_TIM 0x01000000 /* [5212+] */ #define AR5K_SIMR2_CAB_END 0x02000000 /* [5212+] */ -#define AR5K_SIMR2_DTIM_SYNC 0x04000000 /* [5212+] */ -#define AR5K_SIMR2_BCN_TIMEOUT 0x08000000 /* [5212+] */ -#define AR5K_SIMR2_CAB_TIMEOUT 0x10000000 /* [5212+] */ +#define AR5K_SIMR2_DTIM_SYNC 0x04000000 /* DTIM Sync lost [5212+] */ +#define AR5K_SIMR2_BCN_TIMEOUT 0x08000000 /* Beacon Timeout [5212+] */ +#define AR5K_SIMR2_CAB_TIMEOUT 0x10000000 /* CAB Timeout [5212+] */ #define AR5K_SIMR2_DTIM 0x20000000 /* [5212+] */ #define AR5K_SIMR3 0x00b0 /* Register Address [5211+] */ @@ -425,23 +432,69 @@ #define AR5K_SIMR4_QTRIG 0x000003ff /* Mask for QTRIG */ #define AR5K_SIMR4_QTRIG_S 0 +/* + * DMA Debug registers 0-7 + * 0xe0 - 0xfc + */ /* * Decompression mask registers [5212+] */ -#define AR5K_DCM_ADDR 0x0400 /*Decompression mask address (?)*/ -#define AR5K_DCM_DATA 0x0404 /*Decompression mask data (?)*/ +#define AR5K_DCM_ADDR 0x0400 /*Decompression mask address (index) */ +#define AR5K_DCM_DATA 0x0404 /*Decompression mask data */ + +/* + * Wake On Wireless pattern control register [5212+] + */ +#define AR5K_WOW_PCFG 0x0410 /* Register Address */ +#define AR5K_WOW_PCFG_PAT_MATCH_EN 0x00000001 /* Pattern match enable */ +#define AR5K_WOW_PCFG_LONG_FRAME_POL 0x00000002 /* Long frame policy */ +#define AR5K_WOW_PCFG_WOBMISS 0x00000004 /* Wake on bea(con) miss (?) */ +#define AR5K_WOW_PCFG_PAT_0_EN 0x00000100 /* Enable pattern 0 */ +#define AR5K_WOW_PCFG_PAT_1_EN 0x00000200 /* Enable pattern 1 */ +#define AR5K_WOW_PCFG_PAT_2_EN 0x00000400 /* Enable pattern 2 */ +#define AR5K_WOW_PCFG_PAT_3_EN 0x00000800 /* Enable pattern 3 */ +#define AR5K_WOW_PCFG_PAT_4_EN 0x00001000 /* Enable pattern 4 */ +#define AR5K_WOW_PCFG_PAT_5_EN 0x00002000 /* Enable pattern 5 */ + +/* + * Wake On Wireless pattern index register (?) [5212+] + */ +#define AR5K_WOW_PAT_IDX 0x0414 + +/* + * Wake On Wireless pattern data register [5212+] + */ +#define AR5K_WOW_PAT_DATA 0x0418 /* Register Address */ +#define AR5K_WOW_PAT_DATA_0_3_V 0x00000001 /* Pattern 0, 3 value */ +#define AR5K_WOW_PAT_DATA_1_4_V 0x00000100 /* Pattern 1, 4 value */ +#define AR5K_WOW_PAT_DATA_2_5_V 0x00010000 /* Pattern 2, 5 value */ +#define AR5K_WOW_PAT_DATA_0_3_M 0x01000000 /* Pattern 0, 3 mask */ +#define AR5K_WOW_PAT_DATA_1_4_M 0x04000000 /* Pattern 1, 4 mask */ +#define AR5K_WOW_PAT_DATA_2_5_M 0x10000000 /* Pattern 2, 5 mask */ /* * Decompression configuration registers [5212+] */ -#define AR5K_DCCFG 0x0420 +#define AR5K_DCCFG 0x0420 /* Register Address */ +#define AR5K_DCCFG_GLOBAL_EN 0x00000001 /* Enable decompression on all queues */ +#define AR5K_DCCFG_BYPASS_EN 0x00000002 /* Bypass decompression */ +#define AR5K_DCCFG_BCAST_EN 0x00000004 /* Enable decompression for bcast frames */ +#define AR5K_DCCFG_MCAST_EN 0x00000008 /* Enable decompression for mcast frames */ /* * Compression configuration registers [5212+] */ -#define AR5K_CCFG 0x0600 -#define AR5K_CCFG_CUP 0x0604 +#define AR5K_CCFG 0x0600 /* Register Address */ +#define AR5K_CCFG_WINDOW_SIZE 0x00000007 /* Compression window size */ +#define AR5K_CCFG_CPC_EN 0x00000008 /* Enable performance counters */ + +#define AR5K_CCFG_CCU 0x0604 /* Register Address */ +#define AR5K_CCFG_CCU_CUP_EN 0x00000001 /* CCU Catchup enable */ +#define AR5K_CCFG_CCU_CREDIT 0x00000002 /* CCU Credit (field) */ +#define AR5K_CCFG_CCU_CD_THRES 0x00000080 /* CCU Cyc(lic?) debt threshold (field) */ +#define AR5K_CCFG_CCU_CUP_LCNT 0x00010000 /* CCU Catchup lit(?) count */ +#define AR5K_CCFG_CCU_INIT 0x00100200 /* Initial value during reset */ /* * Compression performance counter registers [5212+] @@ -450,7 +503,7 @@ #define AR5K_CPC1 0x0614 /* Compression performance counter 1*/ #define AR5K_CPC2 0x0618 /* Compression performance counter 2 */ #define AR5K_CPC3 0x061c /* Compression performance counter 3 */ -#define AR5K_CPCORN 0x0620 /* Compression performance overrun (?) */ +#define AR5K_CPCOVF 0x0620 /* Compression performance overflow */ /* @@ -466,8 +519,6 @@ * set/clear, which contain status for all queues (we shift by 1 for each * queue). To access these registers easily we define some macros here * that are used inside HAL. For more infos check out *_tx_queue functs. - * - * TODO: Boundary checking on macros (here?) */ /* @@ -513,7 +564,6 @@ #define AR5K_QCU_RDYTIMECFG_BASE 0x0900 /* Register Address - Queue0 RDYTIMECFG */ #define AR5K_QCU_RDYTIMECFG_INTVAL 0x00ffffff /* Ready time interval mask */ #define AR5K_QCU_RDYTIMECFG_INTVAL_S 0 -#define AR5K_QCU_RDYTIMECFG_DURATION 0x00ffffff /* Ready time duration mask */ #define AR5K_QCU_RDYTIMECFG_ENABLE 0x01000000 /* Ready time enable mask */ #define AR5K_QUEUE_RDYTIMECFG(_q) AR5K_QUEUE_REG(AR5K_QCU_RDYTIMECFG_BASE, _q) @@ -534,19 +584,20 @@ */ #define AR5K_QCU_MISC_BASE 0x09c0 /* Register Address -Queue0 MISC */ #define AR5K_QCU_MISC_FRSHED_M 0x0000000f /* Frame sheduling mask */ -#define AR5K_QCU_MISC_FRSHED_ASAP 0 /* ASAP */ -#define AR5K_QCU_MISC_FRSHED_CBR 1 /* Constant Bit Rate */ -#define AR5K_QCU_MISC_FRSHED_DBA_GT 2 /* DMA Beacon alert gated (?) */ -#define AR5K_QCU_MISC_FRSHED_TIM_GT 3 /* Time gated (?) */ +#define AR5K_QCU_MISC_FRSHED_ASAP 0 /* ASAP */ +#define AR5K_QCU_MISC_FRSHED_CBR 1 /* Constant Bit Rate */ +#define AR5K_QCU_MISC_FRSHED_DBA_GT 2 /* DMA Beacon alert gated (?) */ +#define AR5K_QCU_MISC_FRSHED_TIM_GT 3 /* Time gated (?) */ #define AR5K_QCU_MISC_FRSHED_BCN_SENT_GT 4 /* Beacon sent gated (?) */ #define AR5K_QCU_MISC_ONESHOT_ENABLE 0x00000010 /* Oneshot enable */ #define AR5K_QCU_MISC_CBREXP 0x00000020 /* CBR expired (normal queue) */ #define AR5K_QCU_MISC_CBREXP_BCN 0x00000040 /* CBR expired (beacon queue) */ -#define AR5K_QCU_MISC_BCN_ENABLE 0x00000080 /* Beacons enabled */ -#define AR5K_QCU_MISC_CBR_THRES_ENABLE 0x00000100 /* CBR threshold enabled (?) */ -#define AR5K_QCU_MISC_TXE 0x00000200 /* TXE reset when RDYTIME enalbed (?) */ -#define AR5K_QCU_MISC_CBR 0x00000400 /* CBR threshold reset (?) */ -#define AR5K_QCU_MISC_DCU_EARLY 0x00000800 /* DCU reset (?) */ +#define AR5K_QCU_MISC_BCN_ENABLE 0x00000080 /* Enable Beacon use */ +#define AR5K_QCU_MISC_CBR_THRES_ENABLE 0x00000100 /* CBR threshold enabled */ +#define AR5K_QCU_MISC_RDY_VEOL_POLICY 0x00000200 /* TXE reset when RDYTIME enalbed */ +#define AR5K_QCU_MISC_CBR_RESET_CNT 0x00000400 /* CBR threshold (counter) reset */ +#define AR5K_QCU_MISC_DCU_EARLY 0x00000800 /* DCU early termination */ +#define AR5K_QCU_MISC_DCU_CMP_EN 0x00001000 /* Enable frame compression */ #define AR5K_QUEUE_MISC(_q) AR5K_QUEUE_REG(AR5K_QCU_MISC_BASE, _q) @@ -555,7 +606,7 @@ */ #define AR5K_QCU_STS_BASE 0x0a00 /* Register Address - Queue0 STS */ #define AR5K_QCU_STS_FRMPENDCNT 0x00000003 /* Frames pending counter */ -#define AR5K_QCU_STS_CBREXPCNT 0x0000ff00 /* CBR expired counter (?) */ +#define AR5K_QCU_STS_CBREXPCNT 0x0000ff00 /* CBR expired counter */ #define AR5K_QUEUE_STATUS(_q) AR5K_QUEUE_REG(AR5K_QCU_STS_BASE, _q) /* @@ -569,9 +620,11 @@ */ #define AR5K_QCU_CBB_SELECT 0x0b00 #define AR5K_QCU_CBB_ADDR 0x0b04 +#define AR5K_QCU_CBB_ADDR_S 9 /* * QCU compression buffer configuration register [5212+] + * (buffer size) */ #define AR5K_QCU_CBCFG 0x0b08 @@ -652,80 +705,100 @@ * No lockout means there is no special handling. */ #define AR5K_DCU_MISC_BASE 0x1100 /* Register Address -Queue0 DCU_MISC */ -#define AR5K_DCU_MISC_BACKOFF 0x000007ff /* Mask for backoff setting (?) */ +#define AR5K_DCU_MISC_BACKOFF 0x000007ff /* Mask for backoff threshold */ #define AR5K_DCU_MISC_BACKOFF_FRAG 0x00000200 /* Enable backoff while bursting */ -#define AR5K_DCU_MISC_HCFPOLL_ENABLE 0x00000800 /* CF - Poll (?) */ -#define AR5K_DCU_MISC_BACKOFF_PERSIST 0x00001000 /* Persistent backoff (?) */ -#define AR5K_DCU_MISC_FRMPRFTCH_ENABLE 0x00002000 /* Enable frame pre-fetch (?) */ +#define AR5K_DCU_MISC_HCFPOLL_ENABLE 0x00000800 /* CF - Poll enable */ +#define AR5K_DCU_MISC_BACKOFF_PERSIST 0x00001000 /* Persistent backoff */ +#define AR5K_DCU_MISC_FRMPRFTCH_ENABLE 0x00002000 /* Enable frame pre-fetch */ #define AR5K_DCU_MISC_VIRTCOL 0x0000c000 /* Mask for Virtual Collision (?) */ -#define AR5K_DCU_MISC_VIRTCOL_NORMAL 0 -#define AR5K_DCU_MISC_VIRTCOL_MODIFIED 1 -#define AR5K_DCU_MISC_VIRTCOL_IGNORE 2 -#define AR5K_DCU_MISC_BCN_ENABLE 0x00010000 /* Beacon enable (?) */ +#define AR5K_DCU_MISC_VIRTCOL_NORMAL 0 +#define AR5K_DCU_MISC_VIRTCOL_MODIFIED 1 +#define AR5K_DCU_MISC_VIRTCOL_IGNORE 2 +#define AR5K_DCU_MISC_BCN_ENABLE 0x00010000 /* Enable Beacon use */ #define AR5K_DCU_MISC_ARBLOCK_CTL 0x00060000 /* Arbiter lockout control mask */ #define AR5K_DCU_MISC_ARBLOCK_CTL_S 17 -#define AR5K_DCU_MISC_ARBLOCK_CTL_NONE 0 /* No arbiter lockout */ +#define AR5K_DCU_MISC_ARBLOCK_CTL_NONE 0 /* No arbiter lockout */ #define AR5K_DCU_MISC_ARBLOCK_CTL_INTFRM 1 /* Intra-frame lockout */ #define AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL 2 /* Global lockout */ -#define AR5K_DCU_MISC_ARBLOCK_IGNORE 0x00080000 -#define AR5K_DCU_MISC_SEQ_NUM_INCR_DIS 0x00100000 /* Disable sequence number increment (?) */ -#define AR5K_DCU_MISC_POST_FR_BKOFF_DIS 0x00200000 /* Disable post-frame backoff (?) */ -#define AR5K_DCU_MISC_VIRT_COLL_POLICY 0x00400000 /* Virtual Collision policy (?) */ -#define AR5K_DCU_MISC_BLOWN_IFS_POLICY 0x00800000 +#define AR5K_DCU_MISC_ARBLOCK_IGNORE 0x00080000 /* Ignore Arbiter lockout */ +#define AR5K_DCU_MISC_SEQ_NUM_INCR_DIS 0x00100000 /* Disable sequence number increment */ +#define AR5K_DCU_MISC_POST_FR_BKOFF_DIS 0x00200000 /* Disable post-frame backoff */ +#define AR5K_DCU_MISC_VIRT_COLL_POLICY 0x00400000 /* Virtual Collision cw policy */ +#define AR5K_DCU_MISC_BLOWN_IFS_POLICY 0x00800000 /* Blown IFS policy (?) */ #define AR5K_DCU_MISC_SEQNUM_CTL 0x01000000 /* Sequence number control (?) */ #define AR5K_QUEUE_DFS_MISC(_q) AR5K_QUEUE_REG(AR5K_DCU_MISC_BASE, _q) /* * DCU frame sequence number registers */ -#define AR5K_DCU_SEQNUM_BASE 0x1140 -#define AR5K_DCU_SEQNUM_M 0x00000fff +#define AR5K_DCU_SEQNUM_BASE 0x1140 +#define AR5K_DCU_SEQNUM_M 0x00000fff #define AR5K_QUEUE_DFS_SEQNUM(_q) AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q) /* - * DCU global IFS SIFS registers + * DCU global IFS SIFS register */ #define AR5K_DCU_GBL_IFS_SIFS 0x1030 #define AR5K_DCU_GBL_IFS_SIFS_M 0x0000ffff /* - * DCU global IFS slot interval registers + * DCU global IFS slot interval register */ #define AR5K_DCU_GBL_IFS_SLOT 0x1070 #define AR5K_DCU_GBL_IFS_SLOT_M 0x0000ffff /* - * DCU global IFS EIFS registers + * DCU global IFS EIFS register */ #define AR5K_DCU_GBL_IFS_EIFS 0x10b0 #define AR5K_DCU_GBL_IFS_EIFS_M 0x0000ffff /* - * DCU global IFS misc registers + * DCU global IFS misc register + * + * LFSR stands for Linear Feedback Shift Register + * and it's used for generating pseudo-random + * number sequences. + * + * (If i understand corectly, random numbers are + * used for idle sensing -multiplied with cwmin/max etc-) */ #define AR5K_DCU_GBL_IFS_MISC 0x10f0 /* Register Address */ -#define AR5K_DCU_GBL_IFS_MISC_LFSR_SLICE 0x00000007 -#define AR5K_DCU_GBL_IFS_MISC_TURBO_MODE 0x00000008 /* Turbo mode (?) */ -#define AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC 0x000003f0 /* SIFS Duration mask (?) */ -#define AR5K_DCU_GBL_IFS_MISC_USEC_DUR 0x000ffc00 -#define AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY 0x00300000 +#define AR5K_DCU_GBL_IFS_MISC_LFSR_SLICE 0x00000007 /* LFSR Slice Select */ +#define AR5K_DCU_GBL_IFS_MISC_TURBO_MODE 0x00000008 /* Turbo mode */ +#define AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC 0x000003f0 /* SIFS Duration mask */ +#define AR5K_DCU_GBL_IFS_MISC_USEC_DUR 0x000ffc00 /* USEC Duration mask */ +#define AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY 0x00300000 /* DCU Arbiter delay mask */ +#define AR5K_DCU_GBL_IFS_MISC_SIFS_CNT_RST 0x00400000 /* SIFC cnt reset policy (?) */ +#define AR5K_DCU_GBL_IFS_MISC_AIFS_CNT_RST 0x00800000 /* AIFS cnt reset policy (?) */ +#define AR5K_DCU_GBL_IFS_MISC_RND_LFSR_SL_DIS 0x01000000 /* Disable random LFSR slice */ /* * DCU frame prefetch control register */ -#define AR5K_DCU_FP 0x1230 +#define AR5K_DCU_FP 0x1230 /* Register Address */ +#define AR5K_DCU_FP_NOBURST_DCU_EN 0x00000001 /* Enable non-burst prefetch on DCU (?) */ +#define AR5K_DCU_FP_NOBURST_EN 0x00000010 /* Enable non-burst prefetch (?) */ +#define AR5K_DCU_FP_BURST_DCU_EN 0x00000020 /* Enable burst prefetch on DCU (?) */ /* * DCU transmit pause control/status register */ #define AR5K_DCU_TXP 0x1270 /* Register Address */ -#define AR5K_DCU_TXP_M 0x000003ff /* Tx pause mask (?) */ -#define AR5K_DCU_TXP_STATUS 0x00010000 /* Tx pause status (?) */ +#define AR5K_DCU_TXP_M 0x000003ff /* Tx pause mask */ +#define AR5K_DCU_TXP_STATUS 0x00010000 /* Tx pause status */ + +/* + * DCU transmit filter table 0 (32 entries) + */ +#define AR5K_DCU_TX_FILTER_0_BASE 0x1038 +#define AR5K_DCU_TX_FILTER_0(_n) (AR5K_DCU_TX_FILTER_0_BASE + (_n * 64)) /* - * DCU transmit filter register + * DCU transmit filter table 1 (16 entries) */ -#define AR5K_DCU_TX_FILTER 0x1038 +#define AR5K_DCU_TX_FILTER_1_BASE 0x103c +#define AR5K_DCU_TX_FILTER_1(_n) (AR5K_DCU_TX_FILTER_1_BASE + ((_n - 32) * 64)) /* * DCU clear transmit filter register @@ -739,9 +812,6 @@ /* * Reset control register - * - * 4 and 8 are not used in 5211/5212 and - * 2 means "baseband reset" on 5211/5212. */ #define AR5K_RESET_CTL 0x4000 /* Register Address */ #define AR5K_RESET_CTL_PCU 0x00000001 /* Protocol Control Unit reset */ @@ -765,6 +835,7 @@ #define AR5K_SLEEP_CTL_SLE_SLP 0x00010000 /* Force chip sleep */ #define AR5K_SLEEP_CTL_SLE_ALLOW 0x00020000 #define AR5K_SLEEP_CTL_SLE_UNITS 0x00000008 /* [5211+] */ +/* more bits */ /* * Interrupt pending register @@ -776,13 +847,14 @@ * Sleep force register */ #define AR5K_SFR 0x400c -#define AR5K_SFR_M 0x00000001 +#define AR5K_SFR_EN 0x00000001 /* * PCI configuration register */ #define AR5K_PCICFG 0x4010 /* Register Address */ #define AR5K_PCICFG_EEAE 0x00000001 /* Eeprom access enable [5210] */ +#define AR5K_PCICFG_SLEEP_CLOCK_EN 0x00000002 /* Enable sleep clock (?) */ #define AR5K_PCICFG_CLKRUNEN 0x00000004 /* CLKRUN enable [5211+] */ #define AR5K_PCICFG_EESIZE 0x00000018 /* Mask for EEPROM size [5211+] */ #define AR5K_PCICFG_EESIZE_S 3 @@ -798,19 +870,21 @@ #define AR5K_PCICFG_CBEFIX_DIS 0x00000400 /* Disable CBE fix (?) */ #define AR5K_PCICFG_SL_INTEN 0x00000800 /* Enable interrupts when asleep (?) */ #define AR5K_PCICFG_LED_BCTL 0x00001000 /* Led blink (?) [5210] */ -#define AR5K_PCICFG_SL_INPEN 0x00002800 /* Sleep even whith pending interrupts (?) */ +#define AR5K_PCICFG_UNK 0x00001000 /* Passed on some parts durring attach (?) */ +#define AR5K_PCICFG_SL_INPEN 0x00002000 /* Sleep even whith pending interrupts (?) */ #define AR5K_PCICFG_SPWR_DN 0x00010000 /* Mask for power status */ #define AR5K_PCICFG_LEDMODE 0x000e0000 /* Ledmode [5211+] */ #define AR5K_PCICFG_LEDMODE_PROP 0x00000000 /* Blink on standard traffic [5211+] */ #define AR5K_PCICFG_LEDMODE_PROM 0x00020000 /* Default mode (blink on any traffic) [5211+] */ #define AR5K_PCICFG_LEDMODE_PWR 0x00040000 /* Some other blinking mode (?) [5211+] */ #define AR5K_PCICFG_LEDMODE_RAND 0x00060000 /* Random blinking (?) [5211+] */ -#define AR5K_PCICFG_LEDBLINK 0x00700000 +#define AR5K_PCICFG_LEDBLINK 0x00700000 /* Led blink rate */ #define AR5K_PCICFG_LEDBLINK_S 20 -#define AR5K_PCICFG_LEDSLOW 0x00800000 /* Slow led blink rate (?) [5211+] */ +#define AR5K_PCICFG_LEDSLOW 0x00800000 /* Slowest led blink rate [5211+] */ #define AR5K_PCICFG_LEDSTATE \ (AR5K_PCICFG_LED | AR5K_PCICFG_LEDMODE | \ AR5K_PCICFG_LEDBLINK | AR5K_PCICFG_LEDSLOW) +#define AR5K_PCICFG_SLEEP_CLOCK_RATE 0x03000000 /* Sleep clock rate (field) */ /* * "General Purpose Input/Output" (GPIO) control register @@ -947,7 +1021,7 @@ #define AR5K_EEPROM_VERSION_4_4 0x4004 #define AR5K_EEPROM_VERSION_4_5 0x4005 #define AR5K_EEPROM_VERSION_4_6 0x4006 /* has ee_scaled_cck_delta */ -#define AR5K_EEPROM_VERSION_4_7 0x3007 +#define AR5K_EEPROM_VERSION_4_7 0x4007 #define AR5K_EEPROM_MODE_11A 0 #define AR5K_EEPROM_MODE_11B 1 @@ -1023,10 +1097,14 @@ #define AR5K_EEPROM_STAT_WRDONE 0x00000008 /* EEPROM write successful */ /* - * EEPROM config register (?) + * EEPROM config register */ -#define AR5K_EEPROM_CFG 0x6010 - +#define AR5K_EEPROM_CFG 0x6010 /* Register Addres */ +#define AR5K_EEPROM_CFG_SIZE_OVR 0x00000001 +#define AR5K_EEPROM_CFG_WR_WAIT_DIS 0x00000004 /* Disable write wait */ +#define AR5K_EEPROM_CFG_CLK_RATE 0x00000018 /* Clock rate */ +#define AR5K_EEPROM_CFG_PROT_KEY 0x00ffff00 /* Protectio key */ +#define AR5K_EEPROM_CFG_LIND_EN 0x01000000 /* Enable length indicator (?) */ /* @@ -1050,7 +1128,7 @@ #define AR5K_STA_ID1 0x8004 /* Register Address */ #define AR5K_STA_ID1_AP 0x00010000 /* Set AP mode */ #define AR5K_STA_ID1_ADHOC 0x00020000 /* Set Ad-Hoc mode */ -#define AR5K_STA_ID1_PWR_SV 0x00040000 /* Power save reporting (?) */ +#define AR5K_STA_ID1_PWR_SV 0x00040000 /* Power save reporting */ #define AR5K_STA_ID1_NO_KEYSRCH 0x00080000 /* No key search */ #define AR5K_STA_ID1_NO_PSPOLL 0x00100000 /* No power save polling [5210] */ #define AR5K_STA_ID1_PCF_5211 0x00100000 /* Enable PCF on [5211+] */ @@ -1059,9 +1137,13 @@ AR5K_STA_ID1_PCF_5210 : AR5K_STA_ID1_PCF_5211) #define AR5K_STA_ID1_DEFAULT_ANTENNA 0x00200000 /* Use default antenna */ #define AR5K_STA_ID1_DESC_ANTENNA 0x00400000 /* Update antenna from descriptor */ -#define AR5K_STA_ID1_RTS_DEF_ANTENNA 0x00800000 /* Use default antenna for RTS (?) */ -#define AR5K_STA_ID1_ACKCTS_6MB 0x01000000 /* Use 6Mbit/s for ACK/CTS (?) */ +#define AR5K_STA_ID1_RTS_DEF_ANTENNA 0x00800000 /* Use default antenna for RTS */ +#define AR5K_STA_ID1_ACKCTS_6MB 0x01000000 /* Use 6Mbit/s for ACK/CTS */ #define AR5K_STA_ID1_BASE_RATE_11B 0x02000000 /* Use 11b base rate (for ACK/CTS ?) [5211+] */ +#define AR5K_STA_ID1_SELF_GEN_SECTORE 0x04000000 /* Self generate sectore (?) */ +#define AR5K_STA_ID1_CRYPT_MIC_EN 0x08000000 /* Enable MIC */ +#define AR5K_STA_ID1_KEYSRCH_MODE 0x10000000 /* Keysearch mode (?) */ +#define AR5K_STA_ID1_PRESERVE_SEQ_NUM 0x20000000 /* Preserve sequence number */ /* * First BSSID register (MAC address, lower 32bits) @@ -1117,7 +1199,7 @@ * * Retry limit register for 5210 (no QCU/DCU so it's done in PCU) */ -#define AR5K_NODCU_RETRY_LMT 0x801c /*Register Address */ +#define AR5K_NODCU_RETRY_LMT 0x801c /* Register Address */ #define AR5K_NODCU_RETRY_LMT_SH_RETRY 0x0000000f /* Short retry limit mask */ #define AR5K_NODCU_RETRY_LMT_SH_RETRY_S 0 #define AR5K_NODCU_RETRY_LMT_LG_RETRY 0x000000f0 /* Long retry mask */ @@ -1136,9 +1218,9 @@ #define AR5K_USEC_5211 0x801c /* Register Address [5211+] */ #define AR5K_USEC (ah->ah_version == AR5K_AR5210 ? \ AR5K_USEC_5210 : AR5K_USEC_5211) -#define AR5K_USEC_1 0x0000007f +#define AR5K_USEC_1 0x0000007f /* clock cycles for 1us */ #define AR5K_USEC_1_S 0 -#define AR5K_USEC_32 0x00003f80 +#define AR5K_USEC_32 0x00003f80 /* clock cycles for 1us while on 32Mhz clock */ #define AR5K_USEC_32_S 7 #define AR5K_USEC_TX_LATENCY_5211 0x007fc000 #define AR5K_USEC_TX_LATENCY_5211_S 14 @@ -1152,16 +1234,16 @@ /* * PCU beacon control register */ -#define AR5K_BEACON_5210 0x8024 -#define AR5K_BEACON_5211 0x8020 +#define AR5K_BEACON_5210 0x8024 /*Register Address [5210] */ +#define AR5K_BEACON_5211 0x8020 /*Register Address [5211+] */ #define AR5K_BEACON (ah->ah_version == AR5K_AR5210 ? \ AR5K_BEACON_5210 : AR5K_BEACON_5211) -#define AR5K_BEACON_PERIOD 0x0000ffff +#define AR5K_BEACON_PERIOD 0x0000ffff /* Mask for beacon period */ #define AR5K_BEACON_PERIOD_S 0 -#define AR5K_BEACON_TIM 0x007f0000 +#define AR5K_BEACON_TIM 0x007f0000 /* Mask for TIM offset */ #define AR5K_BEACON_TIM_S 16 -#define AR5K_BEACON_ENABLE 0x00800000 -#define AR5K_BEACON_RESET_TSF 0x01000000 +#define AR5K_BEACON_ENABLE 0x00800000 /* Enable beacons */ +#define AR5K_BEACON_RESET_TSF 0x01000000 /* Force TSF reset */ /* * CFP period register @@ -1234,7 +1316,6 @@ /* * Receive filter register - * TODO: Get these out of ar5xxx.h on ath5k */ #define AR5K_RX_FILTER_5210 0x804c /* Register Address [5210] */ #define AR5K_RX_FILTER_5211 0x803c /* Register Address [5211+] */ @@ -1307,11 +1388,11 @@ #define AR5K_DIAG_SW_5211 0x8048 /* Register Address [5211+] */ #define AR5K_DIAG_SW (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_5210 : AR5K_DIAG_SW_5211) -#define AR5K_DIAG_SW_DIS_WEP_ACK 0x00000001 -#define AR5K_DIAG_SW_DIS_ACK 0x00000002 /* Disable ACKs (?) */ -#define AR5K_DIAG_SW_DIS_CTS 0x00000004 /* Disable CTSs (?) */ -#define AR5K_DIAG_SW_DIS_ENC 0x00000008 /* Disable encryption (?) */ -#define AR5K_DIAG_SW_DIS_DEC 0x00000010 /* Disable decryption (?) */ +#define AR5K_DIAG_SW_DIS_WEP_ACK 0x00000001 /* Disable ACKs if WEP key is invalid */ +#define AR5K_DIAG_SW_DIS_ACK 0x00000002 /* Disable ACKs */ +#define AR5K_DIAG_SW_DIS_CTS 0x00000004 /* Disable CTSs */ +#define AR5K_DIAG_SW_DIS_ENC 0x00000008 /* Disable encryption */ +#define AR5K_DIAG_SW_DIS_DEC 0x00000010 /* Disable decryption */ #define AR5K_DIAG_SW_DIS_TX 0x00000020 /* Disable transmit [5210] */ #define AR5K_DIAG_SW_DIS_RX_5210 0x00000040 /* Disable recieve */ #define AR5K_DIAG_SW_DIS_RX_5211 0x00000020 @@ -1329,13 +1410,13 @@ #define AR5K_DIAG_SW_CHAN_INFO_5211 0x00000100 #define AR5K_DIAG_SW_CHAN_INFO (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_CHAN_INFO_5210 : AR5K_DIAG_SW_CHAN_INFO_5211) -#define AR5K_DIAG_SW_EN_SCRAM_SEED_5211 0x00000200 /* Scrambler seed (?) */ +#define AR5K_DIAG_SW_EN_SCRAM_SEED_5211 0x00000200 /* Enable scrambler seed */ #define AR5K_DIAG_SW_EN_SCRAM_SEED_5210 0x00000400 #define AR5K_DIAG_SW_EN_SCRAM_SEED (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_EN_SCRAM_SEED_5210 : AR5K_DIAG_SW_EN_SCRAM_SEED_5211) #define AR5K_DIAG_SW_ECO_ENABLE 0x00000400 /* [5211+] */ #define AR5K_DIAG_SW_SCVRAM_SEED 0x0003f800 /* [5210] */ -#define AR5K_DIAG_SW_SCRAM_SEED_M 0x0001fc00 /* Scrambler seed mask (?) */ +#define AR5K_DIAG_SW_SCRAM_SEED_M 0x0001fc00 /* Scrambler seed mask */ #define AR5K_DIAG_SW_SCRAM_SEED_S 10 #define AR5K_DIAG_SW_DIS_SEQ_INC 0x00040000 /* Disable seqnum increment (?)[5210] */ #define AR5K_DIAG_SW_FRAME_NV0_5210 0x00080000 @@ -1344,6 +1425,7 @@ AR5K_DIAG_SW_FRAME_NV0_5210 : AR5K_DIAG_SW_FRAME_NV0_5211) #define AR5K_DIAG_SW_OBSPT_M 0x000c0000 #define AR5K_DIAG_SW_OBSPT_S 18 +/* more bits */ /* * TSF (clock) register (lower 32 bits) @@ -1369,15 +1451,34 @@ /* * ADDAC test register [5211+] */ -#define AR5K_ADDAC_TEST 0x8054 -#define AR5K_ADDAC_TEST_TXCONT 0x00000001 +#define AR5K_ADDAC_TEST 0x8054 /* Register Address */ +#define AR5K_ADDAC_TEST_TXCONT 0x00000001 /* Test continuous tx */ +#define AR5K_ADDAC_TEST_TST_MODE 0x00000002 /* Test mode */ +#define AR5K_ADDAC_TEST_LOOP_EN 0x00000004 /* Enable loop */ +#define AR5K_ADDAC_TEST_LOOP_LEN 0x00000008 /* Loop length (field) */ +#define AR5K_ADDAC_TEST_USE_U8 0x00004000 /* Use upper 8 bits */ +#define AR5K_ADDAC_TEST_MSB 0x00008000 /* State of MSB */ +#define AR5K_ADDAC_TEST_TRIG_SEL 0x00010000 /* Trigger select */ +#define AR5K_ADDAC_TEST_TRIG_PTY 0x00020000 /* Trigger polarity */ +#define AR5K_ADDAC_TEST_RXCONT 0x00040000 /* Continuous capture */ +#define AR5K_ADDAC_TEST_CAPTURE 0x00080000 /* Begin capture */ +#define AR5K_ADDAC_TEST_TST_ARM 0x00100000 /* Test ARM (Adaptive Radio Mode ?) */ /* * Default antenna register [5211+] */ #define AR5K_DEFAULT_ANTENNA 0x8058 +/* + * Frame control QoS mask register (?) [5211+] + * (FC_QOS_MASK) + */ +#define AR5K_FRAME_CTL_QOSM 0x805c +/* + * Seq mask register (?) [5211+] + */ +#define AR5K_SEQ_MASK 0x8060 /* * Retry count register [5210] @@ -1449,124 +1550,242 @@ /* * XR (eXtended Range) mode register */ -#define AR5K_XRMODE 0x80c0 -#define AR5K_XRMODE_POLL_TYPE_M 0x0000003f +#define AR5K_XRMODE 0x80c0 /* Register Address */ +#define AR5K_XRMODE_POLL_TYPE_M 0x0000003f /* Mask for Poll type (?) */ #define AR5K_XRMODE_POLL_TYPE_S 0 -#define AR5K_XRMODE_POLL_SUBTYPE_M 0x0000003c +#define AR5K_XRMODE_POLL_SUBTYPE_M 0x0000003c /* Mask for Poll subtype (?) */ #define AR5K_XRMODE_POLL_SUBTYPE_S 2 -#define AR5K_XRMODE_POLL_WAIT_ALL 0x00000080 -#define AR5K_XRMODE_SIFS_DELAY 0x000fff00 -#define AR5K_XRMODE_FRAME_HOLD_M 0xfff00000 +#define AR5K_XRMODE_POLL_WAIT_ALL 0x00000080 /* Wait for poll */ +#define AR5K_XRMODE_SIFS_DELAY 0x000fff00 /* Mask for SIFS delay */ +#define AR5K_XRMODE_FRAME_HOLD_M 0xfff00000 /* Mask for frame hold (?) */ #define AR5K_XRMODE_FRAME_HOLD_S 20 /* * XR delay register */ -#define AR5K_XRDELAY 0x80c4 -#define AR5K_XRDELAY_SLOT_DELAY_M 0x0000ffff +#define AR5K_XRDELAY 0x80c4 /* Register Address */ +#define AR5K_XRDELAY_SLOT_DELAY_M 0x0000ffff /* Mask for slot delay */ #define AR5K_XRDELAY_SLOT_DELAY_S 0 -#define AR5K_XRDELAY_CHIRP_DELAY_M 0xffff0000 +#define AR5K_XRDELAY_CHIRP_DELAY_M 0xffff0000 /* Mask for CHIRP data delay */ #define AR5K_XRDELAY_CHIRP_DELAY_S 16 /* * XR timeout register */ -#define AR5K_XRTIMEOUT 0x80c8 -#define AR5K_XRTIMEOUT_CHIRP_M 0x0000ffff +#define AR5K_XRTIMEOUT 0x80c8 /* Register Address */ +#define AR5K_XRTIMEOUT_CHIRP_M 0x0000ffff /* Mask for CHIRP timeout */ #define AR5K_XRTIMEOUT_CHIRP_S 0 -#define AR5K_XRTIMEOUT_POLL_M 0xffff0000 +#define AR5K_XRTIMEOUT_POLL_M 0xffff0000 /* Mask for Poll timeout */ #define AR5K_XRTIMEOUT_POLL_S 16 /* * XR chirp register */ -#define AR5K_XRCHIRP 0x80cc -#define AR5K_XRCHIRP_SEND 0x00000001 -#define AR5K_XRCHIRP_GAP 0xffff0000 +#define AR5K_XRCHIRP 0x80cc /* Register Address */ +#define AR5K_XRCHIRP_SEND 0x00000001 /* Send CHIRP */ +#define AR5K_XRCHIRP_GAP 0xffff0000 /* Mask for CHIRP gap (?) */ /* * XR stomp register */ -#define AR5K_XRSTOMP 0x80d0 -#define AR5K_XRSTOMP_TX 0x00000001 -#define AR5K_XRSTOMP_RX_ABORT 0x00000002 -#define AR5K_XRSTOMP_RSSI_THRES 0x0000ff00 +#define AR5K_XRSTOMP 0x80d0 /* Register Address */ +#define AR5K_XRSTOMP_TX 0x00000001 /* Stomp Tx (?) */ +#define AR5K_XRSTOMP_RX 0x00000002 /* Stomp Rx (?) */ +#define AR5K_XRSTOMP_TX_RSSI 0x00000004 /* Stomp Tx RSSI (?) */ +#define AR5K_XRSTOMP_TX_BSSID 0x00000008 /* Stomp Tx BSSID (?) */ +#define AR5K_XRSTOMP_DATA 0x00000010 /* Stomp data (?)*/ +#define AR5K_XRSTOMP_RSSI_THRES 0x0000ff00 /* Mask for XR RSSI threshold */ /* * First enhanced sleep register */ -#define AR5K_SLEEP0 0x80d4 -#define AR5K_SLEEP0_NEXT_DTIM 0x0007ffff +#define AR5K_SLEEP0 0x80d4 /* Register Address */ +#define AR5K_SLEEP0_NEXT_DTIM 0x0007ffff /* Mask for next DTIM (?) */ #define AR5K_SLEEP0_NEXT_DTIM_S 0 -#define AR5K_SLEEP0_ASSUME_DTIM 0x00080000 -#define AR5K_SLEEP0_ENH_SLEEP_EN 0x00100000 -#define AR5K_SLEEP0_CABTO 0xff000000 +#define AR5K_SLEEP0_ASSUME_DTIM 0x00080000 /* Assume DTIM */ +#define AR5K_SLEEP0_ENH_SLEEP_EN 0x00100000 /* Enable enchanced sleep control */ +#define AR5K_SLEEP0_CABTO 0xff000000 /* Mask for CAB Time Out */ #define AR5K_SLEEP0_CABTO_S 24 /* * Second enhanced sleep register */ -#define AR5K_SLEEP1 0x80d8 -#define AR5K_SLEEP1_NEXT_TIM 0x0007ffff +#define AR5K_SLEEP1 0x80d8 /* Register Address */ +#define AR5K_SLEEP1_NEXT_TIM 0x0007ffff /* Mask for next TIM (?) */ #define AR5K_SLEEP1_NEXT_TIM_S 0 -#define AR5K_SLEEP1_BEACON_TO 0xff000000 +#define AR5K_SLEEP1_BEACON_TO 0xff000000 /* Mask for Beacon Time Out */ #define AR5K_SLEEP1_BEACON_TO_S 24 /* * Third enhanced sleep register */ -#define AR5K_SLEEP2 0x80dc -#define AR5K_SLEEP2_TIM_PER 0x0000ffff +#define AR5K_SLEEP2 0x80dc /* Register Address */ +#define AR5K_SLEEP2_TIM_PER 0x0000ffff /* Mask for TIM period (?) */ #define AR5K_SLEEP2_TIM_PER_S 0 -#define AR5K_SLEEP2_DTIM_PER 0xffff0000 +#define AR5K_SLEEP2_DTIM_PER 0xffff0000 /* Mask for DTIM period (?) */ #define AR5K_SLEEP2_DTIM_PER_S 16 /* * BSSID mask registers */ -#define AR5K_BSS_IDM0 0x80e0 -#define AR5K_BSS_IDM1 0x80e4 +#define AR5K_BSS_IDM0 0x80e0 /* Upper bits */ +#define AR5K_BSS_IDM1 0x80e4 /* Lower bits */ /* * TX power control (TPC) register + * + * XXX: PCDAC steps (0.5dbm) or DBM ? + * + * XXX: Mask changes for newer chips to 7f + * like tx power table ? */ -#define AR5K_TXPC 0x80e8 -#define AR5K_TXPC_ACK_M 0x0000003f +#define AR5K_TXPC 0x80e8 /* Register Address */ +#define AR5K_TXPC_ACK_M 0x0000003f /* Mask for ACK tx power */ #define AR5K_TXPC_ACK_S 0 -#define AR5K_TXPC_CTS_M 0x00003f00 +#define AR5K_TXPC_CTS_M 0x00003f00 /* Mask for CTS tx power */ #define AR5K_TXPC_CTS_S 8 -#define AR5K_TXPC_CHIRP_M 0x003f0000 +#define AR5K_TXPC_CHIRP_M 0x003f0000 /* Mask for CHIRP tx power */ #define AR5K_TXPC_CHIRP_S 22 /* * Profile count registers */ -#define AR5K_PROFCNT_TX 0x80ec -#define AR5K_PROFCNT_RX 0x80f0 -#define AR5K_PROFCNT_RXCLR 0x80f4 -#define AR5K_PROFCNT_CYCLE 0x80f8 +#define AR5K_PROFCNT_TX 0x80ec /* Tx count */ +#define AR5K_PROFCNT_RX 0x80f0 /* Rx count */ +#define AR5K_PROFCNT_RXCLR 0x80f4 /* Clear Rx count */ +#define AR5K_PROFCNT_CYCLE 0x80f8 /* Cycle count (?) */ + +/* + * Quiet (period) control registers (?) + */ +#define AR5K_QUIET_CTL1 0x80fc /* Register Address */ +#define AR5K_QUIET_CTL1_NEXT_QT 0x0000ffff /* Mask for next quiet (period?) (?) */ +#define AR5K_QUIET_CTL1_QT_EN 0x00010000 /* Enable quiet (period?) */ +#define AR5K_QUIET_CTL2 0x8100 /* Register Address */ +#define AR5K_QUIET_CTL2_QT_PER 0x0000ffff /* Mask for quiet period (?) */ +#define AR5K_QUIET_CTL2_QT_DUR 0xffff0000 /* Mask for quiet duration (?) */ /* * TSF parameter register */ -#define AR5K_TSF_PARM 0x8104 -#define AR5K_TSF_PARM_INC_M 0x000000ff +#define AR5K_TSF_PARM 0x8104 /* Register Address */ +#define AR5K_TSF_PARM_INC_M 0x000000ff /* Mask for TSF increment */ #define AR5K_TSF_PARM_INC_S 0 +/* + * QoS register (?) + */ +#define AR5K_QOS 0x8108 /* Register Address */ +#define AR5K_QOS_NOACK_2BIT_VALUES 0x00000000 /* (field) */ +#define AR5K_QOS_NOACK_BIT_OFFSET 0x00000020 /* (field) */ +#define AR5K_QOS_NOACK_BYTE_OFFSET 0x00000080 /* (field) */ + /* * PHY error filter register */ #define AR5K_PHY_ERR_FIL 0x810c -#define AR5K_PHY_ERR_FIL_RADAR 0x00000020 -#define AR5K_PHY_ERR_FIL_OFDM 0x00020000 -#define AR5K_PHY_ERR_FIL_CCK 0x02000000 +#define AR5K_PHY_ERR_FIL_RADAR 0x00000020 /* Radar signal */ +#define AR5K_PHY_ERR_FIL_OFDM 0x00020000 /* OFDM false detect (ANI) */ +#define AR5K_PHY_ERR_FIL_CCK 0x02000000 /* CCK false detect (ANI) */ + +/* + * XR latency register + */ +#define AR5K_XRLAT_TX 0x8110 /* - * Rate duration register + * ACK SIFS register + */ +#define AR5K_ACKSIFS 0x8114 /* Register Address */ +#define AR5K_ACKSIFS_INC 0x00000000 /* ACK SIFS Increment (field) */ + +/* + * MIC QoS control register (?) + */ +#define AR5K_MIC_QOS_CTL 0x8118 /* Register Address */ +#define AR5K_MIC_QOS_CTL_0 0x00000001 /* MIC QoS control 0 (?) */ +#define AR5K_MIC_QOS_CTL_1 0x00000004 /* MIC QoS control 1 (?) */ +#define AR5K_MIC_QOS_CTL_2 0x00000010 /* MIC QoS control 2 (?) */ +#define AR5K_MIC_QOS_CTL_3 0x00000040 /* MIC QoS control 3 (?) */ +#define AR5K_MIC_QOS_CTL_4 0x00000100 /* MIC QoS control 4 (?) */ +#define AR5K_MIC_QOS_CTL_5 0x00000400 /* MIC QoS control 5 (?) */ +#define AR5K_MIC_QOS_CTL_6 0x00001000 /* MIC QoS control 6 (?) */ +#define AR5K_MIC_QOS_CTL_7 0x00004000 /* MIC QoS control 7 (?) */ +#define AR5K_MIC_QOS_CTL_MQ_EN 0x00010000 /* Enable MIC QoS */ + +/* + * MIC QoS select register (?) + */ +#define AR5K_MIC_QOS_SEL 0x811c +#define AR5K_MIC_QOS_SEL_0 0x00000001 +#define AR5K_MIC_QOS_SEL_1 0x00000010 +#define AR5K_MIC_QOS_SEL_2 0x00000100 +#define AR5K_MIC_QOS_SEL_3 0x00001000 +#define AR5K_MIC_QOS_SEL_4 0x00010000 +#define AR5K_MIC_QOS_SEL_5 0x00100000 +#define AR5K_MIC_QOS_SEL_6 0x01000000 +#define AR5K_MIC_QOS_SEL_7 0x10000000 + +/* + * Misc mode control register (?) + */ +#define AR5K_MISC_MODE 0x8120 /* Register Address */ +#define AR5K_MISC_MODE_FBSSID_MATCH 0x00000001 /* Force BSSID match */ +#define AR5K_MISC_MODE_ACKSIFS_MEM 0x00000002 /* ACK SIFS memory (?) */ +/* more bits */ + +/* + * OFDM Filter counter + */ +#define AR5K_OFDM_FIL_CNT 0x8124 + +/* + * CCK Filter counter + */ +#define AR5K_CCK_FIL_CNT 0x8128 + +/* + * PHY Error Counters (?) + */ +#define AR5K_PHYERR_CNT1 0x812c +#define AR5K_PHYERR_CNT1_MASK 0x8130 + +#define AR5K_PHYERR_CNT2 0x8134 +#define AR5K_PHYERR_CNT2_MASK 0x8138 + +/* + * TSF Threshold register (?) + */ +#define AR5K_TSF_THRES 0x813c + +/* + * Rate -> ACK SIFS mapping table (32 entries) + */ +#define AR5K_RATE_ACKSIFS_BASE 0x8680 /* Register Address */ +#define AR5K_RATE_ACKSIFS(_n) (AR5K_RATE_ACKSIFS_BSE + ((_n) << 2)) +#define AR5K_RATE_ACKSIFS_NORMAL 0x00000001 /* Normal SIFS (field) */ +#define AR5K_RATE_ACKSIFS_TURBO 0x00000400 /* Turbo SIFS (field) */ + +/* + * Rate -> duration mapping table (32 entries) */ #define AR5K_RATE_DUR_BASE 0x8700 #define AR5K_RATE_DUR(_n) (AR5K_RATE_DUR_BASE + ((_n) << 2)) +/* + * Rate -> db mapping table + * (8 entries, each one has 4 8bit fields) + */ +#define AR5K_RATE2DB_BASE 0x87c0 +#define AR5K_RATE2DB(_n) (AR5K_RATE2DB_BASE + ((_n) << 2)) + +/* + * db -> Rate mapping table + * (8 entries, each one has 4 8bit fields) + */ +#define AR5K_DB2RATE_BASE 0x87e0 +#define AR5K_DB2RATE(_n) (AR5K_DB2RATE_BASE + ((_n) << 2)) + /*===5212 end===*/ /* @@ -1613,12 +1832,34 @@ /*===PHY REGISTERS===*/ /* - * PHY register + * PHY registers start */ #define AR5K_PHY_BASE 0x9800 #define AR5K_PHY(_n) (AR5K_PHY_BASE + ((_n) << 2)) -#define AR5K_PHY_SHIFT_2GHZ 0x00004007 -#define AR5K_PHY_SHIFT_5GHZ 0x00000007 + +/* + * TST_2 (Misc config parameters) + */ +#define AR5K_PHY_TST2 0x9800 /* Register Address */ +#define AR5K_PHY_TST2_TRIG_SEL 0x00000001 /* Trigger select (?) (field ?) */ +#define AR5K_PHY_TST2_TRIG 0x00000010 /* Trigger (?) (field ?) */ +#define AR5K_PHY_TST2_CBUS_MODE 0x00000100 /* Cardbus mode (?) */ +/* bit reserved */ +#define AR5K_PHY_TST2_CLK32 0x00000400 /* CLK_OUT is CLK32 (32Khz external) */ +#define AR5K_PHY_TST2_CHANCOR_DUMP_EN 0x00000800 /* Enable Chancor dump (?) */ +#define AR5K_PHY_TST2_EVEN_CHANCOR_DUMP 0x00001000 /* Even Chancor dump (?) */ +#define AR5K_PHY_TST2_RFSILENT_EN 0x00002000 /* Enable RFSILENT */ +#define AR5K_PHY_TST2_ALT_RFDATA 0x00004000 /* Alternate RFDATA (5-2GHz switch) */ +#define AR5K_PHY_TST2_MINI_OBS_EN 0x00008000 /* Enable mini OBS (?) */ +#define AR5K_PHY_TST2_RX2_IS_RX5_INV 0x00010000 /* 2GHz rx path is the 5GHz path inverted (?) */ +#define AR5K_PHY_TST2_SLOW_CLK160 0x00020000 /* Slow CLK160 (?) */ +#define AR5K_PHY_TST2_AGC_OBS_SEL_3 0x00040000 /* AGC OBS Select 3 (?) */ +#define AR5K_PHY_TST2_BBB_OBS_SEL 0x00080000 /* BB OBS Select (field ?) */ +#define AR5K_PHY_TST2_ADC_OBS_SEL 0x00800000 /* ADC OBS Select (field ?) */ +#define AR5K_PHY_TST2_RX_CLR_SEL 0x08000000 /* RX Clear Select (?) */ +#define AR5K_PHY_TST2_FORCE_AGC_CLR 0x10000000 /* Force AGC clear (?) */ +#define AR5K_PHY_SHIFT_2GHZ 0x00004007 /* Used to access 2GHz radios */ +#define AR5K_PHY_SHIFT_5GHZ 0x00000007 /* Used to access 5GHz radios (default) */ /* * PHY frame control register [5110] /turbo mode register [5111+] @@ -1630,18 +1871,21 @@ * a "turbo mode register" for 5110. We treat this one as * a frame control register for 5110 below. */ -#define AR5K_PHY_TURBO 0x9804 -#define AR5K_PHY_TURBO_MODE 0x00000001 -#define AR5K_PHY_TURBO_SHORT 0x00000002 +#define AR5K_PHY_TURBO 0x9804 /* Register Address */ +#define AR5K_PHY_TURBO_MODE 0x00000001 /* Enable turbo mode */ +#define AR5K_PHY_TURBO_SHORT 0x00000002 /* Short mode (20Mhz channels) (?) */ /* * PHY agility command register + * (aka TST_1) */ -#define AR5K_PHY_AGC 0x9808 -#define AR5K_PHY_AGC_DISABLE 0x08000000 +#define AR5K_PHY_AGC 0x9808 /* Register Address */ +#define AR5K_PHY_TST1 0x9808 +#define AR5K_PHY_AGC_DISABLE 0x08000000 /* Disable AGC to A2 (?)*/ +#define AR5K_PHY_TST1_TXHOLD 0x00003800 /* Set tx hold (?) */ /* - * PHY timing register [5112+] + * PHY timing register 3 [5112+] */ #define AR5K_PHY_TIMING_3 0x9814 #define AR5K_PHY_TIMING_3_DSC_MAN 0xfffe0000 @@ -1657,26 +1901,81 @@ /* * PHY activation register */ -#define AR5K_PHY_ACT 0x981c -#define AR5K_PHY_ACT_ENABLE 0x00000001 -#define AR5K_PHY_ACT_DISABLE 0x00000002 +#define AR5K_PHY_ACT 0x981c /* Register Address */ +#define AR5K_PHY_ACT_ENABLE 0x00000001 /* Activate PHY */ +#define AR5K_PHY_ACT_DISABLE 0x00000002 /* Deactivate PHY */ + +/* + * PHY RF control registers + * (i think these are delay times, + * these calibration values exist + * in EEPROM) + */ +#define AR5K_PHY_RF_CTL2 0x9824 /* Register Address */ +#define AR5K_PHY_RF_CTL2_TXF2TXD_START 0x0000000f /* Mask for TX frame to TX d(esc?) start */ + +#define AR5K_PHY_RF_CTL3 0x9828 /* Register Address */ +#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON 0x0000000f /* Mask for TX end to XLNA on */ + +#define AR5K_PHY_RF_CTL4 0x9834 /* Register Address */ +#define AR5K_PHY_RF_CTL4_TXF2XPA_A_ON 0x00000001 /* TX frame to XPA A on (field) */ +#define AR5K_PHY_RF_CTL4_TXF2XPA_B_ON 0x00000100 /* TX frame to XPA B on (field) */ +#define AR5K_PHY_RF_CTL4_TXE2XPA_A_OFF 0x00010000 /* TX end to XPA A off (field) */ +#define AR5K_PHY_RF_CTL4_TXE2XPA_B_OFF 0x01000000 /* TX end to XPA B off (field) */ + +/* + * Pre-Amplifier control register + * (XPA -> external pre-amplifier) + */ +#define AR5K_PHY_PA_CTL 0x9838 /* Register Address */ +#define AR5K_PHY_PA_CTL_XPA_A_HI 0x00000001 /* XPA A high (?) */ +#define AR5K_PHY_PA_CTL_XPA_B_HI 0x00000002 /* XPA B high (?) */ +#define AR5K_PHY_PA_CTL_XPA_A_EN 0x00000004 /* Enable XPA A */ +#define AR5K_PHY_PA_CTL_XPA_B_EN 0x00000008 /* Enable XPA B */ + +/* + * PHY settling register + */ +#define AR5K_PHY_SETTLING 0x9844 /* Register Address */ +#define AR5K_PHY_SETTLING_AGC 0x0000007f /* Mask for AGC settling time */ +#define AR5K_PHY_SETTLING_SWITCH 0x00003f80 /* Mask for Switch settlig time */ + +/* + * PHY Gain registers + */ +#define AR5K_PHY_GAIN 0x9848 /* Register Address */ +#define AR5K_PHY_GAIN_TXRX_ATTEN 0x0003f000 /* Mask for TX-RX Attenuation */ + +#define AR5K_PHY_GAIN_OFFSET 0x984c /* Register Address */ +#define AR5K_PHY_GAIN_OFFSET_RXTX_FLAG 0x00020000 /* RX-TX flag (?) */ + +/* + * Desired size register + * (for more infos read ANI patent) + */ +#define AR5K_PHY_DESIRED_SIZE 0x9850 /* Register Address */ +#define AR5K_PHY_DESIRED_SIZE_ADC 0x000000ff /* Mask for ADC desired size */ +#define AR5K_PHY_DESIRED_SIZE_PGA 0x0000ff00 /* Mask for PGA desired size */ +#define AR5K_PHY_DESIRED_SIZE_TOT 0x0ff00000 /* Mask for Total desired size (?) */ /* * PHY signal register + * (for more infos read ANI patent) */ -#define AR5K_PHY_SIG 0x9858 -#define AR5K_PHY_SIG_FIRSTEP 0x0003f000 +#define AR5K_PHY_SIG 0x9858 /* Register Address */ +#define AR5K_PHY_SIG_FIRSTEP 0x0003f000 /* Mask for FIRSTEP */ #define AR5K_PHY_SIG_FIRSTEP_S 12 -#define AR5K_PHY_SIG_FIRPWR 0x03fc0000 +#define AR5K_PHY_SIG_FIRPWR 0x03fc0000 /* Mask for FIPWR */ #define AR5K_PHY_SIG_FIRPWR_S 18 /* * PHY coarse agility control register + * (for more infos read ANI patent) */ -#define AR5K_PHY_AGCCOARSE 0x985c -#define AR5K_PHY_AGCCOARSE_LO 0x00007f80 +#define AR5K_PHY_AGCCOARSE 0x985c /* Register Address */ +#define AR5K_PHY_AGCCOARSE_LO 0x00007f80 /* Mask for AGC Coarse low */ #define AR5K_PHY_AGCCOARSE_LO_S 7 -#define AR5K_PHY_AGCCOARSE_HI 0x003f8000 +#define AR5K_PHY_AGCCOARSE_HI 0x003f8000 /* Mask for AGC Coarse high */ #define AR5K_PHY_AGCCOARSE_HI_S 15 /* @@ -1689,12 +1988,13 @@ /* * PHY noise floor status register */ -#define AR5K_PHY_NF 0x9864 -#define AR5K_PHY_NF_M 0x000001ff -#define AR5K_PHY_NF_ACTIVE 0x00000100 +#define AR5K_PHY_NF 0x9864 /* Register address */ +#define AR5K_PHY_NF_M 0x000001ff /* Noise floor mask */ +#define AR5K_PHY_NF_ACTIVE 0x00000100 /* Noise floor calibration still active */ #define AR5K_PHY_NF_RVAL(_n) (((_n) >> 19) & AR5K_PHY_NF_M) #define AR5K_PHY_NF_AVAL(_n) (-((_n) ^ AR5K_PHY_NF_M) + 1) #define AR5K_PHY_NF_SVAL(_n) (((_n) & AR5K_PHY_NF_M) | (1 << 9)) +#define AR5K_PHY_NF_THRESH62 0x00001000 /* Thresh62 -check ANI patent- (field) */ /* * PHY ADC saturation register [5110] @@ -1705,6 +2005,30 @@ #define AR5K_PHY_ADCSAT_THR 0x000007e0 #define AR5K_PHY_ADCSAT_THR_S 5 +/* + * PHY Weak ofdm signal detection threshold registers (ANI) [5212+] + */ + +/* High thresholds */ +#define AR5K_PHY_WEAK_OFDM_HIGH_THR 0x9868 +#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT 0x0000001f +#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT_S 0 +#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1 0x00fe0000 +#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1_S 17 +#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2 0x7f000000 +#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_S 24 + +/* Low thresholds */ +#define AR5K_PHY_WEAK_OFDM_LOW_THR 0x986c +#define AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN 0x00000001 +#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT 0x00003f00 +#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT_S 8 +#define AR5K_PHY_WEAK_OFDM_LOW_THR_M1 0x001fc000 +#define AR5K_PHY_WEAK_OFDM_LOW_THR_M1_S 14 +#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2 0x0fe00000 +#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_S 21 + + /* * PHY sleep registers [5112+] */ @@ -1730,6 +2054,8 @@ AR5K_PHY_PLL_44MHZ_5211 : AR5K_PHY_PLL_44MHZ_5212) #define AR5K_PHY_PLL_RF5111 0x00000000 #define AR5K_PHY_PLL_RF5112 0x00000040 +#define AR5K_PHY_PLL_HALF_RATE 0x00000100 +#define AR5K_PHY_PLL_QUARTER_RATE 0x00000200 /* * RF Buffer register @@ -1791,24 +2117,75 @@ #define AR5K_PHY_RFSTG 0x98d4 #define AR5K_PHY_RFSTG_DISABLE 0x00000021 +/* + * PHY Antenna control register + */ +#define AR5K_PHY_ANT_CTL 0x9910 /* Register Address */ +#define AR5K_PHY_ANT_CTL_TXRX_EN 0x00000001 /* Enable TX/RX (?) */ +#define AR5K_PHY_ANT_CTL_SECTORED_ANT 0x00000004 /* Sectored Antenna */ +#define AR5K_PHY_ANT_CTL_HITUNE5 0x00000008 /* Hitune5 (?) */ +#define AR5K_PHY_ANT_CTL_SWTABLE_IDLE 0x00000010 /* Switch table idle (?) */ + /* * PHY receiver delay register [5111+] */ -#define AR5K_PHY_RX_DELAY 0x9914 -#define AR5K_PHY_RX_DELAY_M 0x00003fff +#define AR5K_PHY_RX_DELAY 0x9914 /* Register Address */ +#define AR5K_PHY_RX_DELAY_M 0x00003fff /* Mask for RX activate to receive delay (/100ns) */ + +/* + * PHY max rx length register (?) [5111] + */ +#define AR5K_PHY_MAX_RX_LEN 0x991c /* - * PHY timing I(nphase) Q(adrature) control register [5111+] + * PHY timing register 4 + * I(nphase)/Q(adrature) calibration register [5111+] */ -#define AR5K_PHY_IQ 0x9920 /* Register address */ +#define AR5K_PHY_IQ 0x9920 /* Register Address */ #define AR5K_PHY_IQ_CORR_Q_Q_COFF 0x0000001f /* Mask for q correction info */ #define AR5K_PHY_IQ_CORR_Q_I_COFF 0x000007e0 /* Mask for i correction info */ #define AR5K_PHY_IQ_CORR_Q_I_COFF_S 5 #define AR5K_PHY_IQ_CORR_ENABLE 0x00000800 /* Enable i/q correction */ -#define AR5K_PHY_IQ_CAL_NUM_LOG_MAX 0x0000f000 +#define AR5K_PHY_IQ_CAL_NUM_LOG_MAX 0x0000f000 /* Mask for max number of samples in log scale */ #define AR5K_PHY_IQ_CAL_NUM_LOG_MAX_S 12 #define AR5K_PHY_IQ_RUN 0x00010000 /* Run i/q calibration */ +#define AR5K_PHY_IQ_USE_PT_DF 0x00020000 /* Use pilot track df (?) */ +#define AR5K_PHY_IQ_EARLY_TRIG_THR 0x00200000 /* Early trigger threshold (?) (field) */ +#define AR5K_PHY_IQ_PILOT_MASK_EN 0x10000000 /* Enable pilot mask (?) */ +#define AR5K_PHY_IQ_CHAN_MASK_EN 0x20000000 /* Enable channel mask (?) */ +#define AR5K_PHY_IQ_SPUR_FILT_EN 0x40000000 /* Enable spur filter */ +#define AR5K_PHY_IQ_SPUR_RSSI_EN 0x80000000 /* Enable spur rssi */ +/* + * PHY timing register 5 + * OFDM Self-correlator Cyclic RSSI threshold params + * (Check out bb_cycpwr_thr1 on ANI patent) + */ +#define AR5K_PHY_OFDM_SELFCORR 0x9924 /* Register Address */ +#define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_EN 0x00000001 /* Enable cyclic RSSI thr 1 */ +#define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1 0x000000fe /* Mask for Cyclic RSSI threshold 1 */ +#define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR3 0x00000100 /* Cyclic RSSI threshold 3 (field) (?) */ +#define AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR_EN 0x00008000 /* Enable 1A RSSI threshold (?) */ +#define AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR 0x00010000 /* 1A RSSI threshold (field) (?) */ +#define AR5K_PHY_OFDM_SELFCORR_LSCTHR_HIRSSI 0x00800000 /* Long sc threshold hi rssi (?) */ + +/* + * PHY-only warm reset register + */ +#define AR5K_PHY_WARM_RESET 0x9928 + +/* + * PHY-only control register + */ +#define AR5K_PHY_CTL 0x992c /* Register Address */ +#define AR5K_PHY_CTL_RX_DRAIN_RATE 0x00000001 /* RX drain rate (?) */ +#define AR5K_PHY_CTL_LATE_TX_SIG_SYM 0x00000002 /* Late tx signal symbol (?) */ +#define AR5K_PHY_CTL_GEN_SCRAMBLER 0x00000004 /* Generate scrambler */ +#define AR5K_PHY_CTL_TX_ANT_SEL 0x00000008 /* TX antenna select */ +#define AR5K_PHY_CTL_TX_ANT_STATIC 0x00000010 /* Static TX antenna */ +#define AR5K_PHY_CTL_RX_ANT_SEL 0x00000020 /* RX antenna select */ +#define AR5K_PHY_CTL_RX_ANT_STATIC 0x00000040 /* Static RX antenna */ +#define AR5K_PHY_CTL_LOW_FREQ_SLE_EN 0x00000080 /* Enable low freq sleep */ /* * PHY PAPD probe register [5111+ (?)] @@ -1816,9 +2193,13 @@ * Because it's always 0 in 5211 initialization code */ #define AR5K_PHY_PAPD_PROBE 0x9930 +#define AR5K_PHY_PAPD_PROBE_SH_HI_PAR 0x00000001 +#define AR5K_PHY_PAPD_PROBE_PCDAC_BIAS 0x00000002 +#define AR5K_PHY_PAPD_PROBE_COMP_GAIN 0x00000040 #define AR5K_PHY_PAPD_PROBE_TXPOWER 0x00007e00 #define AR5K_PHY_PAPD_PROBE_TXPOWER_S 9 #define AR5K_PHY_PAPD_PROBE_TX_NEXT 0x00008000 +#define AR5K_PHY_PAPD_PROBE_PREDIST_EN 0x00010000 #define AR5K_PHY_PAPD_PROBE_TYPE 0x01800000 /* [5112+] */ #define AR5K_PHY_PAPD_PROBE_TYPE_S 23 #define AR5K_PHY_PAPD_PROBE_TYPE_OFDM 0 @@ -1848,15 +2229,16 @@ #define AR5K_PHY_FRAME_CTL (ah->ah_version == AR5K_AR5210 ? \ AR5K_PHY_FRAME_CTL_5210 : AR5K_PHY_FRAME_CTL_5211) /*---[5111+]---*/ -#define AR5K_PHY_FRAME_CTL_TX_CLIP 0x00000038 +#define AR5K_PHY_FRAME_CTL_TX_CLIP 0x00000038 /* Mask for tx clip (?) */ #define AR5K_PHY_FRAME_CTL_TX_CLIP_S 3 +#define AR5K_PHY_FRAME_CTL_PREP_CHINFO 0x00010000 /* Prepend chan info */ /*---[5110/5111]---*/ -#define AR5K_PHY_FRAME_CTL_TIMING_ERR 0x01000000 -#define AR5K_PHY_FRAME_CTL_PARITY_ERR 0x02000000 -#define AR5K_PHY_FRAME_CTL_ILLRATE_ERR 0x04000000 /* illegal rate */ -#define AR5K_PHY_FRAME_CTL_ILLLEN_ERR 0x08000000 /* illegal length */ +#define AR5K_PHY_FRAME_CTL_TIMING_ERR 0x01000000 /* PHY timing error */ +#define AR5K_PHY_FRAME_CTL_PARITY_ERR 0x02000000 /* Parity error */ +#define AR5K_PHY_FRAME_CTL_ILLRATE_ERR 0x04000000 /* Illegal rate */ +#define AR5K_PHY_FRAME_CTL_ILLLEN_ERR 0x08000000 /* Illegal length */ #define AR5K_PHY_FRAME_CTL_SERVICE_ERR 0x20000000 -#define AR5K_PHY_FRAME_CTL_TXURN_ERR 0x40000000 /* tx underrun */ +#define AR5K_PHY_FRAME_CTL_TXURN_ERR 0x40000000 /* TX underrun */ #define AR5K_PHY_FRAME_CTL_INI AR5K_PHY_FRAME_CTL_SERVICE_ERR | \ AR5K_PHY_FRAME_CTL_TXURN_ERR | \ AR5K_PHY_FRAME_CTL_ILLLEN_ERR | \ @@ -1914,6 +2296,11 @@ after DFS is enabled */ #define AR5K_PHY_ANT_SWITCH_TABLE_0 0x9960 #define AR5K_PHY_ANT_SWITCH_TABLE_1 0x9964 +/* + * PHY Noise floor threshold + */ +#define AR5K_PHY_NFTHRES 0x9968 + /* * PHY clock sleep registers [5112+] */ @@ -1922,56 +2309,116 @@ after DFS is enabled */ #define AR5K_PHY_SDELAY 0x99f4 #define AR5K_PHY_SDELAY_32MHZ 0x000000ff #define AR5K_PHY_SPENDING 0x99f8 +#define AR5K_PHY_SPENDING_14 0x00000014 +#define AR5K_PHY_SPENDING_18 0x00000018 #define AR5K_PHY_SPENDING_RF5111 0x00000018 -#define AR5K_PHY_SPENDING_RF5112 0x00000014 /* <- i 've only seen this on 2425 dumps ! */ -#define AR5K_PHY_SPENDING_RF5112A 0x0000000e /* but since i only have 5112A-based chips */ -#define AR5K_PHY_SPENDING_RF5424 0x00000012 /* to test it might be also for old 5112. */ +#define AR5K_PHY_SPENDING_RF5112 0x00000014 +/* #define AR5K_PHY_SPENDING_RF5112A 0x0000000e */ +/* #define AR5K_PHY_SPENDING_RF5424 0x00000012 */ +#define AR5K_PHY_SPENDING_RF5413 0x00000014 +#define AR5K_PHY_SPENDING_RF2413 0x00000014 +#define AR5K_PHY_SPENDING_RF2425 0x00000018 /* * Misc PHY/radio registers [5110 - 5111] */ -#define AR5K_BB_GAIN_BASE 0x9b00 /* BaseBand Amplifier Gain table base address */ +#define AR5K_BB_GAIN_BASE 0x9b00 /* BaseBand Amplifier Gain table base address */ #define AR5K_BB_GAIN(_n) (AR5K_BB_GAIN_BASE + ((_n) << 2)) -#define AR5K_RF_GAIN_BASE 0x9a00 /* RF Amplrifier Gain table base address */ +#define AR5K_RF_GAIN_BASE 0x9a00 /* RF Amplrifier Gain table base address */ #define AR5K_RF_GAIN(_n) (AR5K_RF_GAIN_BASE + ((_n) << 2)) /* * PHY timing IQ calibration result register [5111+] */ -#define AR5K_PHY_IQRES_CAL_PWR_I 0x9c10 /* I (Inphase) power value */ -#define AR5K_PHY_IQRES_CAL_PWR_Q 0x9c14 /* Q (Quadrature) power value */ +#define AR5K_PHY_IQRES_CAL_PWR_I 0x9c10 /* I (Inphase) power value */ +#define AR5K_PHY_IQRES_CAL_PWR_Q 0x9c14 /* Q (Quadrature) power value */ #define AR5K_PHY_IQRES_CAL_CORR 0x9c18 /* I/Q Correlation */ /* * PHY current RSSI register [5111+] */ -#define AR5K_PHY_CURRENT_RSSI 0x9c1c +#define AR5K_PHY_CURRENT_RSSI 0x9c1c + +/* + * PHY RF Bus grant register (?) + */ +#define AR5K_PHY_RFBUS_GRANT 0x9c20 + +/* + * PHY ADC test register + */ +#define AR5K_PHY_ADC_TEST 0x9c24 +#define AR5K_PHY_ADC_TEST_I 0x00000001 +#define AR5K_PHY_ADC_TEST_Q 0x00000200 + +/* + * PHY DAC test register + */ +#define AR5K_PHY_DAC_TEST 0x9c28 +#define AR5K_PHY_DAC_TEST_I 0x00000001 +#define AR5K_PHY_DAC_TEST_Q 0x00000200 + +/* + * PHY PTAT register (?) + */ +#define AR5K_PHY_PTAT 0x9c2c + +/* + * PHY Illegal TX rate register [5112+] + */ +#define AR5K_PHY_BAD_TX_RATE 0x9c30 + +/* + * PHY SPUR Power register [5112+] + */ +#define AR5K_PHY_SPUR_PWR 0x9c34 /* Register Address */ +#define AR5K_PHY_SPUR_PWR_I 0x00000001 /* SPUR Power estimate for I (field) */ +#define AR5K_PHY_SPUR_PWR_Q 0x00000100 /* SPUR Power estimate for Q (field) */ +#define AR5K_PHY_SPUR_PWR_FILT 0x00010000 /* Power with SPUR removed (field) */ + +/* + * PHY Channel status register [5112+] (?) + */ +#define AR5K_PHY_CHAN_STATUS 0x9c38 +#define AR5K_PHY_CHAN_STATUS_BT_ACT 0x00000001 +#define AR5K_PHY_CHAN_STATUS_RX_CLR_RAW 0x00000002 +#define AR5K_PHY_CHAN_STATUS_RX_CLR_MAC 0x00000004 +#define AR5K_PHY_CHAN_STATUS_RX_CLR_PAP 0x00000008 + +/* + * PHY PAPD I (power?) table (?) + * (92! entries) + */ +#define AR5K_PHY_PAPD_I_BASE 0xa000 +#define AR5K_PHY_PAPD_I(_n) (AR5K_PHY_PAPD_I_BASE + ((_n) << 2)) /* * PHY PCDAC TX power table */ #define AR5K_PHY_PCDAC_TXPOWER_BASE_5211 0xa180 -#define AR5K_PHY_PCDAC_TXPOWER_BASE_5413 0xa280 -#define AR5K_PHY_PCDAC_TXPOWER_BASE (ah->ah_radio >= AR5K_RF5413 ? \ - AR5K_PHY_PCDAC_TXPOWER_BASE_5413 :\ +#define AR5K_PHY_PCDAC_TXPOWER_BASE_2413 0xa280 +#define AR5K_PHY_PCDAC_TXPOWER_BASE (ah->ah_radio >= AR5K_RF2413 ? \ + AR5K_PHY_PCDAC_TXPOWER_BASE_2413 :\ AR5K_PHY_PCDAC_TXPOWER_BASE_5211) #define AR5K_PHY_PCDAC_TXPOWER(_n) (AR5K_PHY_PCDAC_TXPOWER_BASE + ((_n) << 2)) /* * PHY mode register [5111+] */ -#define AR5K_PHY_MODE 0x0a200 /* Register address */ -#define AR5K_PHY_MODE_MOD 0x00000001 /* PHY Modulation mask*/ +#define AR5K_PHY_MODE 0x0a200 /* Register Address */ +#define AR5K_PHY_MODE_MOD 0x00000001 /* PHY Modulation bit */ #define AR5K_PHY_MODE_MOD_OFDM 0 #define AR5K_PHY_MODE_MOD_CCK 1 -#define AR5K_PHY_MODE_FREQ 0x00000002 /* Freq mode mask */ +#define AR5K_PHY_MODE_FREQ 0x00000002 /* Freq mode bit */ #define AR5K_PHY_MODE_FREQ_5GHZ 0 #define AR5K_PHY_MODE_FREQ_2GHZ 2 -#define AR5K_PHY_MODE_MOD_DYN 0x00000004 /* Dynamic OFDM/CCK mode mask [5112+] */ +#define AR5K_PHY_MODE_MOD_DYN 0x00000004 /* Enable Dynamic OFDM/CCK mode [5112+] */ #define AR5K_PHY_MODE_RAD 0x00000008 /* [5212+] */ #define AR5K_PHY_MODE_RAD_RF5111 0 #define AR5K_PHY_MODE_RAD_RF5112 8 -#define AR5K_PHY_MODE_XR 0x00000010 /* [5112+] */ +#define AR5K_PHY_MODE_XR 0x00000010 /* Enable XR mode [5112+] */ +#define AR5K_PHY_MODE_HALF_RATE 0x00000020 /* Enable Half rate (test) */ +#define AR5K_PHY_MODE_QUARTER_RATE 0x00000040 /* Enable Quarter rat (test) */ /* * PHY CCK transmit control register [5111+ (?)] @@ -1979,6 +2426,15 @@ after DFS is enabled */ #define AR5K_PHY_CCKTXCTL 0xa204 #define AR5K_PHY_CCKTXCTL_WORLD 0x00000000 #define AR5K_PHY_CCKTXCTL_JAPAN 0x00000010 +#define AR5K_PHY_CCKTXCTL_SCRAMBLER_DIS 0x00000001 +#define AR5K_PHY_CCKTXCTK_DAC_SCALE 0x00000004 + +/* + * PHY CCK Cross-correlator Barker RSSI threshold register [5212+] + */ +#define AR5K_PHY_CCK_CROSSCORR 0xa208 +#define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR 0x0000000f +#define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR_S 0 /* * PHY 2GHz gain register [5111+] -- cgit v1.2.3 From ba37746e547e14703a5ac86560c6e056620bc4cf Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Sun, 20 Jul 2008 06:32:32 +0300 Subject: ath5k: Restore saved initval after POST * Restore saved initial value after POST Changes-licensed-under: ISC Signed-off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/hw.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index 42ef41ed5d1..b3b9baa551b 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c @@ -139,6 +139,8 @@ static int ath5k_hw_post(struct ath5k_hw *ah) for (c = 0; c < 2; c++) { cur_reg = regs[c]; + + /* Save previous value */ init_val = ath5k_hw_reg_read(ah, cur_reg); for (i = 0; i < 256; i++) { @@ -170,6 +172,10 @@ static int ath5k_hw_post(struct ath5k_hw *ah) var_pattern = 0x003b080f; ath5k_hw_reg_write(ah, var_pattern, cur_reg); } + + /* Restore previous value */ + ath5k_hw_reg_write(ah, init_val, cur_reg); + } return 0; -- cgit v1.2.3 From e5a4ad0dda8f79a984ba6391af65274b482b6703 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Sun, 20 Jul 2008 06:34:39 +0300 Subject: ath5k: Misc hw_attach fixes * Correctly attach RF2425 * Update SREV values for Radio chips * Update hw_attach to use new SPENDING values * Write a bit after POST for some chips Changes-licensed-under: ISC Signed-off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/ath5k.h | 8 +++-- drivers/net/wireless/ath5k/hw.c | 62 +++++++++++++------------------------- 2 files changed, 26 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index ba35c30d203..9102eea3c8b 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -186,11 +186,13 @@ struct ath5k_srev_name { #define AR5K_SREV_RAD_2111 0x20 #define AR5K_SREV_RAD_5112 0x30 #define AR5K_SREV_RAD_5112A 0x35 +#define AR5K_SREV_RAD_5112B 0x36 #define AR5K_SREV_RAD_2112 0x40 #define AR5K_SREV_RAD_2112A 0x45 -#define AR5K_SREV_RAD_SC0 0x56 /* Found on 2413/2414 */ -#define AR5K_SREV_RAD_SC1 0x63 /* Found on 5413/5414 */ -#define AR5K_SREV_RAD_SC2 0xa2 /* Found on 2424-5/5424 */ +#define AR5K_SREV_RAD_2112B 0x46 +#define AR5K_SREV_RAD_SC0 0x50 /* Found on 2413/2414 */ +#define AR5K_SREV_RAD_SC1 0x60 /* Found on 5413/5414 */ +#define AR5K_SREV_RAD_SC2 0xa0 /* Found on 2424-5/5424 */ #define AR5K_SREV_RAD_5133 0xc0 /* MIMO found on 5418 */ /* IEEE defs */ diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index b3b9baa551b..8cd8659e912 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c @@ -293,67 +293,42 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) /* Identify the radio chip*/ if (ah->ah_version == AR5K_AR5210) { ah->ah_radio = AR5K_RF5110; + /* + * Register returns 0x0/0x04 for radio revision + * so ath5k_hw_radio_revision doesn't parse the value + * correctly. For now we are based on mac's srev to + * identify RF2425 radio. + */ + } else if (srev == AR5K_SREV_VER_AR2425) { + ah->ah_radio = AR5K_RF2425; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425; } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) { ah->ah_radio = AR5K_RF5111; ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111; } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC0) { - ah->ah_radio = AR5K_RF5112; - - if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) { - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112; - } else { - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A; - } - + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112; } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) { ah->ah_radio = AR5K_RF2413; - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413; } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC2) { ah->ah_radio = AR5K_RF5413; - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5133) { - /* AR5424 */ if (srev >= AR5K_SREV_VER_AR5424) { ah->ah_radio = AR5K_RF5413; - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5424; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; /* AR2424 */ } else { ah->ah_radio = AR5K_RF2413; /* For testing */ - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A; + ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413; } - - /* - * Register returns 0x4 for radio revision - * so ath5k_hw_radio_revision doesn't parse the value - * correctly. For now we are based on mac's srev to - * identify RF2425 radio. - */ - } else if (srev == AR5K_SREV_VER_AR2425) { - ah->ah_radio = AR5K_RF2425; - ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112; } - ah->ah_phy = AR5K_PHY(0); /* - * Identify AR5212-based PCI-E cards - * And write some initial settings. - * - * (doing a "strings" on ndis driver - * -ar5211.sys- reveals the following - * pci-e related functions: - * - * pcieClockReq - * pcieRxErrNotify - * pcieL1SKPEnable - * pcieAspm - * pcieDisableAspmOnRfWake - * pciePowerSaveEnable - * - * I guess these point to ClockReq but - * i'm not sure.) + * Write PCI-E power save settings */ if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) { ath5k_hw_reg_write(ah, 0x9248fc00, 0x4080); @@ -375,10 +350,15 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) if (ret) goto err_free; + /* Write AR5K_PCICFG_UNK on 2112B and later chips */ + if (ah->ah_radio_5ghz_revision > AR5K_SREV_RAD_2112B || + srev > AR5K_SREV_VER_AR2413) { + ath5k_hw_reg_write(ah, AR5K_PCICFG_UNK, AR5K_PCICFG); + } + /* * Get card capabilities, values, ... */ - ret = ath5k_eeprom_init(ah); if (ret) { ATH5K_ERR(sc, "unable to init EEPROM\n"); -- cgit v1.2.3 From 2203d6be7ed17af81a1dc35a0af9806086743b02 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Sun, 20 Jul 2008 06:36:52 +0300 Subject: ath5k: Misc hw_reset updates * Update hw_reset to calculate some of the values we were using as static * Increase activation to rx delay Changes-licensed-under: ISC Signed-off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/hw.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index 8cd8659e912..dc51b844c62 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c @@ -847,7 +847,22 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, else ath5k_hw_reg_write(ah, 0x00000000, 0x994c); - ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); + /* Some bits are disabled here, we know nothing about + * register 0xa228 yet, most of the times this ends up + * with a value 0x9b5 -haven't seen any dump with + * a different value- */ + /* Got this from decompiling binary HAL */ + data = ath5k_hw_reg_read(ah, 0xa228); + data &= 0xfffffdff; + ath5k_hw_reg_write(ah, data, 0xa228); + + data = ath5k_hw_reg_read(ah, 0xa228); + data &= 0xfffe03ff; + ath5k_hw_reg_write(ah, data, 0xa228); + data = 0; + + /* Just write 0x9b5 ? */ + /* ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); */ ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK); ath5k_hw_reg_write(ah, 0x00000000, 0xa254); ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL); @@ -864,6 +879,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, else data = 0xffb80d20; ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL); + data = 0; } /* @@ -883,7 +899,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, /* * Write RF registers - * TODO:Does this work on 5211 (5111) ? */ ret = ath5k_hw_rfregs(ah, channel, mode); if (ret) @@ -1048,7 +1063,8 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); /* - * 5111/5112 Specific + * On 5211+ read activation -> rx delay + * and use it. */ if (ah->ah_version != AR5K_AR5210) { data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & @@ -1056,7 +1072,8 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, data = (channel->hw_value & CHANNEL_CCK) ? ((data << 2) / 22) : (data / 10); - udelay(100 + data); + udelay(100 + (2 * data)); + data = 0; } else { mdelay(1); } @@ -1139,6 +1156,12 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK); ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY); ath5k_hw_reg_write(ah, ah->ah_phy_spending, AR5K_PHY_SPENDING); + + data = ath5k_hw_reg_read(ah, AR5K_USEC_5211) & 0xffffc07f ; + data |= (ah->ah_phy_spending == AR5K_PHY_SPENDING_18) ? + 0x00000f80 : 0x00001380 ; + ath5k_hw_reg_write(ah, data, AR5K_USEC_5211); + data = 0; } if (ah->ah_version == AR5K_AR5212) { -- cgit v1.2.3 From e2a0ccebc4ffabc1c7234cfd324299b5a936e0f2 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Sun, 20 Jul 2008 06:38:16 +0300 Subject: ath5k: Do ADC test during reset * Do an ADC test during reset to match recent regdumps Changes-licensed-under: ISC Signed-off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/hw.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index dc51b844c62..3937e46e473 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c @@ -1078,6 +1078,19 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, mdelay(1); } + /* + * Perform ADC test (?) + */ + data = ath5k_hw_reg_read(ah, AR5K_PHY_TST1); + ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1); + for (i = 0; i <= 20; i++) { + if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10)) + break; + udelay(200); + } + ath5k_hw_reg_write(ah, data, AR5K_PHY_TST1); + data = 0; + /* * Enable calibration and wait until completion */ -- cgit v1.2.3 From df75dcddf99647d68f3b6b874effe5365c5024d9 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Sun, 20 Jul 2008 06:41:26 +0300 Subject: ath5k: Reorder calibration calls during reset and update hw_set_power * Update ath5k_hw_reset and add some more documentation about PHY calibration * Fix ath5k_hw_set_power to use AR5K_SLEEP_CTL_SLE_ALLOW for Network sleep * Preserve sleep duration field while setting AR5K_SLEEP_CTL and reduce delays & checks for register's status (got this from decompiling & dumps, it works for me but it needs testing) Changes-licensed-under: ISC Signed-off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/hw.c | 82 +++++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index 3937e46e473..ad1a5b422c8 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c @@ -1092,34 +1092,57 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, data = 0; /* - * Enable calibration and wait until completion + * Start automatic gain calibration + * + * During AGC calibration RX path is re-routed to + * a signal detector so we don't receive anything. + * + * This method is used to calibrate some static offsets + * used together with on-the fly I/Q calibration (the + * one performed via ath5k_hw_phy_calibrate), that doesn't + * interrupt rx path. + * + * If we are in a noisy environment AGC calibration may time + * out. */ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL); + /* At the same time start I/Q calibration for QAM constellation + * -no need for CCK- */ + ah->ah_calibration = false; + if (!(mode == AR5K_MODE_11B)) { + ah->ah_calibration = true; + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, + AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15); + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, + AR5K_PHY_IQ_RUN); + } + + /* Wait for gain calibration to finish (we check for I/Q calibration + * during ath5k_phy_calibrate) */ if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL, 0, false)) { - ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n", + ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n", channel->center_freq); return -EAGAIN; } + /* + * Start noise floor calibration + * + * If we run NF calibration before AGC, it always times out. + * Binary HAL starts NF and AGC calibration at the same time + * and only waits for AGC to finish. I believe that's wrong because + * during NF calibration, rx path is also routed to a detector, so if + * it doesn't finish we won't have RX. + * + * XXX: Find an interval that's OK for all cards... + */ ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq); if (ret) return ret; - ah->ah_calibration = false; - - /* A and G modes can use QAM modulation which requires enabling - * I and Q calibration. Don't bother in B mode. */ - if (!(mode == AR5K_MODE_11B)) { - ah->ah_calibration = true; - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, - AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15); - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, - AR5K_PHY_IQ_RUN); - } - /* * Reset queues and start beacon timers at the end of the reset routine */ @@ -1247,7 +1270,7 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration) { unsigned int i; - u32 staid; + u32 staid, data; ATH5K_TRACE(ah->ah_sc); staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1); @@ -1259,7 +1282,8 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, case AR5K_PM_NETWORK_SLEEP: if (set_chip) ath5k_hw_reg_write(ah, - AR5K_SLEEP_CTL_SLE | sleep_duration, + AR5K_SLEEP_CTL_SLE_ALLOW | + sleep_duration, AR5K_SLEEP_CTL); staid |= AR5K_STA_ID1_PWR_SV; @@ -1274,13 +1298,24 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, break; case AR5K_PM_AWAKE: + + staid &= ~AR5K_STA_ID1_PWR_SV; + if (!set_chip) goto commit; - ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE, - AR5K_SLEEP_CTL); + /* Preserve sleep duration */ + data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL); + if( data & 0xffc00000 ){ + data = 0; + } else { + data = data & 0xfffcffff; + } + + ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); + udelay(15); - for (i = 5000; i > 0; i--) { + for (i = 50; i > 0; i--) { /* Check if the chip did wake up */ if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) & AR5K_PCICFG_SPWR_DN) == 0) @@ -1288,15 +1323,13 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, /* Wait a bit and retry */ udelay(200); - ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE, - AR5K_SLEEP_CTL); + ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); } /* Fail if the chip didn't wake up */ if (i <= 0) return -EIO; - staid &= ~AR5K_STA_ID1_PWR_SV; break; default: @@ -1325,6 +1358,7 @@ void ath5k_hw_start_rx(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR); + ath5k_hw_reg_read(ah, AR5K_CR); } /* @@ -1411,6 +1445,7 @@ int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue) } /* Start queue */ ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); + ath5k_hw_reg_read(ah, AR5K_CR); } else { /* Return if queue is disabled */ if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue)) @@ -1708,6 +1743,7 @@ enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask) * (they will be re-enabled afterwards). */ ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); + ath5k_hw_reg_read(ah, AR5K_IER); old_mask = ah->ah_imr; @@ -3511,7 +3547,7 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE) AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), - AR5K_QCU_MISC_TXE); + AR5K_QCU_MISC_RDY_VEOL_POLICY); } if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE) -- cgit v1.2.3 From 27bcdeed320c8c7dc0f502df43f6465f0d9840f1 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Sun, 20 Jul 2008 06:42:47 +0300 Subject: ath5k: Add RF2425 initial rfgain values * Add initial RF gain settings for RF2425 Changes-licensed-under: ISC Signed-off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/phy.c | 72 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index afd8689e5c0..66af70bd14e 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath5k/phy.c @@ -1020,6 +1020,74 @@ static const struct ath5k_ini_rfgain rfgain_2413[] = { { AR5K_RF_GAIN(63), { 0x000000f9 } }, }; +/* Initial RF Gain settings for RF2425 */ +static const struct ath5k_ini_rfgain rfgain_2425[] = { + { AR5K_RF_GAIN(0), { 0x00000000 } }, + { AR5K_RF_GAIN(1), { 0x00000040 } }, + { AR5K_RF_GAIN(2), { 0x00000080 } }, + { AR5K_RF_GAIN(3), { 0x00000181 } }, + { AR5K_RF_GAIN(4), { 0x000001c1 } }, + { AR5K_RF_GAIN(5), { 0x00000001 } }, + { AR5K_RF_GAIN(6), { 0x00000041 } }, + { AR5K_RF_GAIN(7), { 0x00000081 } }, + { AR5K_RF_GAIN(8), { 0x00000188 } }, + { AR5K_RF_GAIN(9), { 0x000001c8 } }, + { AR5K_RF_GAIN(10), { 0x00000008 } }, + { AR5K_RF_GAIN(11), { 0x00000048 } }, + { AR5K_RF_GAIN(12), { 0x00000088 } }, + { AR5K_RF_GAIN(13), { 0x00000189 } }, + { AR5K_RF_GAIN(14), { 0x000001c9 } }, + { AR5K_RF_GAIN(15), { 0x00000009 } }, + { AR5K_RF_GAIN(16), { 0x00000049 } }, + { AR5K_RF_GAIN(17), { 0x00000089 } }, + { AR5K_RF_GAIN(18), { 0x000001b0 } }, + { AR5K_RF_GAIN(19), { 0x000001f0 } }, + { AR5K_RF_GAIN(20), { 0x00000030 } }, + { AR5K_RF_GAIN(21), { 0x00000070 } }, + { AR5K_RF_GAIN(22), { 0x00000171 } }, + { AR5K_RF_GAIN(23), { 0x000001b1 } }, + { AR5K_RF_GAIN(24), { 0x000001f1 } }, + { AR5K_RF_GAIN(25), { 0x00000031 } }, + { AR5K_RF_GAIN(26), { 0x00000071 } }, + { AR5K_RF_GAIN(27), { 0x000001b8 } }, + { AR5K_RF_GAIN(28), { 0x000001f8 } }, + { AR5K_RF_GAIN(29), { 0x00000038 } }, + { AR5K_RF_GAIN(30), { 0x00000078 } }, + { AR5K_RF_GAIN(31), { 0x000000b8 } }, + { AR5K_RF_GAIN(32), { 0x000001b9 } }, + { AR5K_RF_GAIN(33), { 0x000001f9 } }, + { AR5K_RF_GAIN(34), { 0x00000039 } }, + { AR5K_RF_GAIN(35), { 0x00000079 } }, + { AR5K_RF_GAIN(36), { 0x000000b9 } }, + { AR5K_RF_GAIN(37), { 0x000000f9 } }, + { AR5K_RF_GAIN(38), { 0x000000f9 } }, + { AR5K_RF_GAIN(39), { 0x000000f9 } }, + { AR5K_RF_GAIN(40), { 0x000000f9 } }, + { AR5K_RF_GAIN(41), { 0x000000f9 } }, + { AR5K_RF_GAIN(42), { 0x000000f9 } }, + { AR5K_RF_GAIN(43), { 0x000000f9 } }, + { AR5K_RF_GAIN(44), { 0x000000f9 } }, + { AR5K_RF_GAIN(45), { 0x000000f9 } }, + { AR5K_RF_GAIN(46), { 0x000000f9 } }, + { AR5K_RF_GAIN(47), { 0x000000f9 } }, + { AR5K_RF_GAIN(48), { 0x000000f9 } }, + { AR5K_RF_GAIN(49), { 0x000000f9 } }, + { AR5K_RF_GAIN(50), { 0x000000f9 } }, + { AR5K_RF_GAIN(51), { 0x000000f9 } }, + { AR5K_RF_GAIN(52), { 0x000000f9 } }, + { AR5K_RF_GAIN(53), { 0x000000f9 } }, + { AR5K_RF_GAIN(54), { 0x000000f9 } }, + { AR5K_RF_GAIN(55), { 0x000000f9 } }, + { AR5K_RF_GAIN(56), { 0x000000f9 } }, + { AR5K_RF_GAIN(57), { 0x000000f9 } }, + { AR5K_RF_GAIN(58), { 0x000000f9 } }, + { AR5K_RF_GAIN(59), { 0x000000f9 } }, + { AR5K_RF_GAIN(60), { 0x000000f9 } }, + { AR5K_RF_GAIN(61), { 0x000000f9 } }, + { AR5K_RF_GAIN(62), { 0x000000f9 } }, + { AR5K_RF_GAIN(63), { 0x000000f9 } }, +}; + static const struct ath5k_gain_opt rfgain_opt_5112 = { 1, 8, @@ -1588,8 +1656,8 @@ int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq) freq = 0; /* only 2Ghz */ break; case AR5K_RF2425: - ath5k_rfg = rfgain_2413; - size = ARRAY_SIZE(rfgain_2413); + ath5k_rfg = rfgain_2425; + size = ARRAY_SIZE(rfgain_2425); freq = 0; /* only 2Ghz */ break; default: -- cgit v1.2.3 From cc6323c7d8c231d83e592ff9f7acf2cac5e016f7 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Sun, 20 Jul 2008 06:44:43 +0300 Subject: ath5k: Update channel functions * Add channel function for RF2425 (got this from decompiling binary HAL, i have no idea why there is a 5GHz section but i'm looking into it) * Update RF5112 channel function (also got this from decompiling binary HAL) * Set JAPAN setting for channel 14 on all PHY chips Changes-licensed-under: ISC Signed-off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/phy.c | 59 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index 66af70bd14e..cbc362d2071 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath5k/phy.c @@ -1898,9 +1898,6 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, data = data0 = data1 = data2 = 0; c = channel->center_freq; - /* - * Set the channel on the RF5112 or newer - */ if (c < 4800) { if (!((c - 2224) % 5)) { data0 = ((2 * (c - 704)) - 3040) / 10; @@ -1912,7 +1909,7 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, return -EINVAL; data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8); - } else { + } else if ((c - (c % 5)) != 2 || c > 5435) { if (!(c % 20) && c >= 5120) { data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); data2 = ath5k_hw_bitswap(3, 2); @@ -1924,6 +1921,9 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, data2 = ath5k_hw_bitswap(1, 2); } else return -EINVAL; + } else { + data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8); + data2 = ath5k_hw_bitswap(0, 2); } data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001; @@ -1934,6 +1934,45 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, return 0; } +/* + * Set the channel on the RF2425 + */ +static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + u32 data, data0, data2; + u16 c; + + data = data0 = data2 = 0; + c = channel->center_freq; + + if (c < 4800) { + data0 = ath5k_hw_bitswap((c - 2272), 8); + data2 = 0; + /* ? 5GHz ? */ + } else if ((c - (c % 5)) != 2 || c > 5435) { + if (!(c % 20) && c < 5120) + data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); + else if (!(c % 10)) + data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8); + else if (!(c % 5)) + data0 = ath5k_hw_bitswap((c - 4800) / 5, 8); + else + return -EINVAL; + data2 = ath5k_hw_bitswap(1, 2); + } else { + data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8); + data2 = ath5k_hw_bitswap(0, 2); + } + + data = (data0 << 4) | data2 << 2 | 0x1001; + + ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER); + ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5); + + return 0; +} + /* * Set a channel on the radio chip */ @@ -1963,6 +2002,9 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) case AR5K_RF5111: ret = ath5k_hw_rf5111_channel(ah, channel); break; + case AR5K_RF2425: + ret = ath5k_hw_rf2425_channel(ah, channel); + break; default: ret = ath5k_hw_rf5112_channel(ah, channel); break; @@ -1971,6 +2013,15 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) if (ret) return ret; + /* Set JAPAN setting for channel 14 */ + if (channel->center_freq == 2484) { + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL, + AR5K_PHY_CCKTXCTL_JAPAN); + } else { + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL, + AR5K_PHY_CCKTXCTL_WORLD); + } + ah->ah_current_channel.center_freq = channel->center_freq; ah->ah_current_channel.hw_value = channel->hw_value; ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false; -- cgit v1.2.3 From f860ee26db51c478fd70039bd4902912a8d93993 Mon Sep 17 00:00:00 2001 From: Nick Kossifidis Date: Sun, 20 Jul 2008 06:47:12 +0300 Subject: ath5k: Update phy calibration functions * Enable I/Q calibration each time we have correction results (we were only enabling calibration during reset). If we don't we commit the same results each time calibration routine is called. * Add some documentation and a TODO on nf calibration * Return -EAGAIN on noise floor timeout/failure Changes-licensed-under: ISC Signed-off-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/phy.c | 54 +++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index cbc362d2071..fa0d47faf57 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath5k/phy.c @@ -2052,6 +2052,8 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \ * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7 * + * XXX: Since during noise floor calibration antennas are detached according to + * the patent, we should stop tx queues here. */ int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq) @@ -2061,7 +2063,7 @@ ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq) s32 noise_floor; /* - * Enable noise floor calibration and wait until completion + * Enable noise floor calibration */ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF); @@ -2071,7 +2073,7 @@ ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq) if (ret) { ATH5K_ERR(ah->ah_sc, "noise floor calibration timeout (%uMHz)\n", freq); - return ret; + return -EAGAIN; } /* Wait until the noise floor is calibrated and read the value */ @@ -2093,7 +2095,7 @@ ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq) if (noise_floor > AR5K_TUNE_NOISE_FLOOR) { ATH5K_ERR(ah->ah_sc, "noise floor calibration failed (%uMHz)\n", freq); - return -EIO; + return -EAGAIN; } ah->ah_noise_floor = noise_floor; @@ -2206,38 +2208,66 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, } /* - * Perform a PHY calibration on RF5111/5112 + * Perform a PHY calibration on RF5111/5112 and newer chips */ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel) { u32 i_pwr, q_pwr; s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd; + int i; ATH5K_TRACE(ah->ah_sc); if (!ah->ah_calibration || - ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN) + ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN) goto done; - ah->ah_calibration = false; + /* Calibration has finished, get the results and re-run */ + for (i = 0; i <= 10; i++) { + iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR); + i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I); + q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q); + } - iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR); - i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I); - q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q); i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7; - q_coffd = q_pwr >> 6; + q_coffd = q_pwr >> 7; + /* No correction */ if (i_coffd == 0 || q_coffd == 0) goto done; i_coff = ((-iq_corr) / i_coffd) & 0x3f; - q_coff = (((s32)i_pwr / q_coffd) - 64) & 0x1f; - /* Commit new IQ value */ + /* Boundary check */ + if (i_coff > 31) + i_coff = 31; + if (i_coff < -32) + i_coff = -32; + + q_coff = (((s32)i_pwr / q_coffd) - 128) & 0x1f; + + /* Boundary check */ + if (q_coff > 15) + q_coff = 15; + if (q_coff < -16) + q_coff = -16; + + /* Commit new I/Q value */ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE | ((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S)); + /* Re-enable calibration -if we don't we'll commit + * the same values again and again */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, + AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15); + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_RUN); + done: + + /* TODO: Separate noise floor calibration from I/Q calibration + * since noise floor calibration interrupts rx path while I/Q + * calibration doesn't. We don't need to run noise floor calibration + * as often as I/Q calibration.*/ ath5k_hw_noise_floor_calibration(ah, channel->center_freq); /* Request RF gain */ -- cgit v1.2.3 From dc1968e7b7862bcd2d358c1be6119c011992bdd2 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 23 Jul 2008 13:17:34 +0200 Subject: Ath5k: mask out unneeded interrupts Mask out previously demanded interrupt flags because we set new ones. Don't allow mixing them after switch from sta to ibss and vice versa. Signed-off-by: Jiri Slaby Cc: Nick Kossifidis Cc: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/base.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index ff3fad794b6..ebf19bc11f5 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -2170,6 +2170,7 @@ ath5k_beacon_config(struct ath5k_softc *sc) ath5k_hw_set_intr(ah, 0); sc->bmisscount = 0; + sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA); if (sc->opmode == IEEE80211_IF_TYPE_STA) { sc->imask |= AR5K_INT_BMISS; -- cgit v1.2.3 From 8de394f60235a825b32f30441290a44251eca45d Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 24 Jul 2008 18:22:55 +0200 Subject: ath5k: remove obsolete declaration of struct ieee80211_hw_mode Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville --- drivers/net/wireless/ath5k/debug.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath5k/debug.h b/drivers/net/wireless/ath5k/debug.h index 2cf8d18b10e..ffc52939330 100644 --- a/drivers/net/wireless/ath5k/debug.h +++ b/drivers/net/wireless/ath5k/debug.h @@ -63,7 +63,6 @@ struct ath5k_softc; struct ath5k_hw; -struct ieee80211_hw_mode; struct sk_buff; struct ath5k_buf; -- cgit v1.2.3 From 143b09efb74efd3328f57d7a4bd6d7663c1d6497 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 24 Jul 2008 21:33:42 +0300 Subject: iwlwifi: don't stop queue in the middle of fragmented packet This patch avoids stopping queue in the middle of the fragmented packet. It is required that there will be ~10 (max packet/min fragment) or 16 (4 bits of frag number) free tfds all the time. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index f72cd0bf6aa..0182e4da8e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -962,16 +962,16 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (ret) return ret; - if ((iwl_queue_space(q) < q->high_mark) - && priv->mac80211_registered) { + if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) { if (wait_write_ptr) { spin_lock_irqsave(&priv->lock, flags); txq->need_update = 1; iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); + } else { + ieee80211_stop_queue(priv->hw, + skb_get_queue_mapping(skb)); } - - ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb)); } return 0; -- cgit v1.2.3 From 7c7e6af37dad30632103497a72a1273d18ec55fe Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Fri, 25 Jul 2008 19:08:11 +0200 Subject: Rtl8187 PATCH add usb ID for asus wireless link This patch from Davide Cavalca adds a usb ID for an rtl8187L device. Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/rtl8187_dev.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 91fc2c765d9..4c7ff61a1a9 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -649,6 +649,7 @@ config RTL8187 Trendnet TEW-424UB ASUS P5B Deluxe Toshiba Satellite Pro series of laptops + Asus Wireless Link Thanks to Realtek for their support! diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 177988efd66..461aa26164c 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -31,6 +31,8 @@ MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver"); MODULE_LICENSE("GPL"); static struct usb_device_id rtl8187_table[] __devinitdata = { + /* Asus */ + {USB_DEVICE(0x0b05, 0x171d), .driver_info = DEVICE_RTL8187}, /* Realtek */ {USB_DEVICE(0x0bda, 0x8187), .driver_info = DEVICE_RTL8187}, {USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B}, -- cgit v1.2.3 From d2b690714cd7d328561bfb9bf941edd6a3316a85 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 27 Jul 2008 15:06:05 +0200 Subject: rt2x00: Fix access permissions on debugfs files Although most rt2x00 debugfs files don't contain information which could compromise network security, it is better to set the access permissions to root only. This will be required when HW crypto is implemented, because it could be possible to read the HW key from the registers. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00debug.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 300cf061035..6bee1d611bb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -372,9 +372,6 @@ static ssize_t rt2x00debug_write_##__name(struct file *file, \ if (*offset) \ return 0; \ \ - if (!capable(CAP_NET_ADMIN)) \ - return -EPERM; \ - \ if (intf->offset_##__name >= debug->__name.word_count) \ return -EINVAL; \ \ @@ -454,7 +451,7 @@ static struct dentry *rt2x00debug_create_file_driver(const char *name, data += sprintf(data, "compiled: %s %s\n", __DATE__, __TIME__); blob->size = strlen(blob->data); - return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob); + return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob); } static struct dentry *rt2x00debug_create_file_chipset(const char *name, @@ -482,7 +479,7 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name, data += sprintf(data, "rf length: %d\n", debug->rf.word_count); blob->size = strlen(blob->data); - return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob); + return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob); } void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) @@ -517,7 +514,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) if (IS_ERR(intf->chipset_entry)) goto exit; - intf->dev_flags = debugfs_create_file("dev_flags", S_IRUGO, + intf->dev_flags = debugfs_create_file("dev_flags", S_IRUSR, intf->driver_folder, intf, &rt2x00debug_fop_dev_flags); if (IS_ERR(intf->dev_flags)) @@ -532,7 +529,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) ({ \ (__intf)->__name##_off_entry = \ debugfs_create_u32(__stringify(__name) "_offset", \ - S_IRUGO | S_IWUSR, \ + S_IRUSR | S_IWUSR, \ (__intf)->register_folder, \ &(__intf)->offset_##__name); \ if (IS_ERR((__intf)->__name##_off_entry)) \ @@ -540,7 +537,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) \ (__intf)->__name##_val_entry = \ debugfs_create_file(__stringify(__name) "_value", \ - S_IRUGO | S_IWUSR, \ + S_IRUSR | S_IWUSR, \ (__intf)->register_folder, \ (__intf), &rt2x00debug_fop_##__name);\ if (IS_ERR((__intf)->__name##_val_entry)) \ @@ -560,7 +557,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) goto exit; intf->queue_frame_dump_entry = - debugfs_create_file("dump", S_IRUGO, intf->queue_folder, + debugfs_create_file("dump", S_IRUSR, intf->queue_folder, intf, &rt2x00debug_fop_queue_dump); if (IS_ERR(intf->queue_frame_dump_entry)) goto exit; @@ -569,7 +566,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) init_waitqueue_head(&intf->frame_dump_waitqueue); intf->queue_stats_entry = - debugfs_create_file("queue", S_IRUGO, intf->queue_folder, + debugfs_create_file("queue", S_IRUSR, intf->queue_folder, intf, &rt2x00debug_fop_queue_stats); return; -- cgit v1.2.3 From ada662f3eb6231ab27f5e6366d4e5c395d25edd3 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 27 Jul 2008 15:06:21 +0200 Subject: rt2x00: Fix partial antenna configuration The if-statement to determine the new TX/RX antenna configuration was incomplete. It lacks the general else-clause when the antenna wasn't changed. This is a correct event, since it can occur when only one of the antenna's has been changed or when the new configuration is being forced (like when the interface has just been added). Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00config.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 3f89516e833..d134c3be539 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -254,6 +254,8 @@ config: libconf.ant.rx = default_ant->rx; else if (active_ant->rx == ANTENNA_SW_DIVERSITY) libconf.ant.rx = ANTENNA_B; + else + libconf.ant.rx = active_ant->rx; if (conf->antenna_sel_tx) libconf.ant.tx = conf->antenna_sel_tx; @@ -261,6 +263,8 @@ config: libconf.ant.tx = default_ant->tx; else if (active_ant->tx == ANTENNA_SW_DIVERSITY) libconf.ant.tx = ANTENNA_B; + else + libconf.ant.tx = active_ant->tx; } if (flags & CONFIG_UPDATE_SLOT_TIME) { -- cgit v1.2.3 From e6d3e902088ac5da77b074f513e3cb80422ff471 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 27 Jul 2008 15:06:50 +0200 Subject: rt2x00: rt61pci needs another millisecond after firmware upload After the hardware has indicated the firmware upload has completed and the device is ready, we should wait another millisecond to make sure the device is really ready to continue. Without this timout, bringing the interface down and up again will fail due to incorrect register initialization. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index fbe2a652e01..087e90b328c 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1003,6 +1003,11 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, return -EBUSY; } + /* + * Hardware needs another millisecond before it is ready. + */ + msleep(1); + /* * Reset MAC and BBP registers. */ -- cgit v1.2.3 From 8d8acd46fb7e962ac04baef5a118d431fae6b0f6 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 28 Jul 2008 10:20:12 +0200 Subject: rt2x00: Fix VGC lower bound initialization When the EEPROM_BBPTUNE_VGC word is valid, we should override EEPROM_BBPTUNE_VGCLOWER field with the BBP value. And we should _not_ do that when EEPROM_BBPTUNE_R17 is valid. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 3078417b326..c6f6eb6e17a 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1376,6 +1376,9 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp); rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word); EEPROM(rt2x00dev, "BBPtune vgc: 0x%04x\n", word); + } else { + rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp); + rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word); } rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &word); @@ -1384,9 +1387,6 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_HIGH, 0x41); rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R17, word); EEPROM(rt2x00dev, "BBPtune r17: 0x%04x\n", word); - } else { - rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp); - rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word); } rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &word); -- cgit v1.2.3 From d4764b29b6e0f1608e397930677928e5a3f62bba Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 28 Jul 2008 10:21:16 +0200 Subject: rt2x00: Sequence counter should be protected in irqsave The sequence counter can be accessed in IRQ context, which means the lock protecting the counter should be irqsave. To prevent making the entire intf->lock irqsave without reason, create a new lock which only protects the sequence counter. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 6 ++++++ drivers/net/wireless/rt2x00/rt2x00mac.c | 1 + drivers/net/wireless/rt2x00/rt2x00queue.c | 5 +++-- 3 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index db2dc976d83..8b10ea41b20 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -368,6 +368,12 @@ struct rt2x00_intf { #define DELAYED_CONFIG_ERP 0x00000002 #define DELAYED_LED_ASSOC 0x00000004 + /* + * Software sequence counter, this is only required + * for hardware which doesn't support hardware + * sequence counting. + */ + spinlock_t seqlock; u16 seqno; }; diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index c3ee4ecba79..bd422fd6a89 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -247,6 +247,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, rt2x00dev->intf_sta_count++; spin_lock_init(&intf->lock); + spin_lock_init(&intf->seqlock); intf->beacon = entry; if (conf->type == IEEE80211_IF_TYPE_AP) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 3b27f6aa860..898cdd7f57d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -128,6 +128,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, unsigned int data_length; unsigned int duration; unsigned int residual; + unsigned long irqflags; memset(txdesc, 0, sizeof(*txdesc)); @@ -213,14 +214,14 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, * sequence counter given by mac80211. */ if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - spin_lock(&intf->lock); + spin_lock_irqsave(&intf->seqlock, irqflags); if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)) intf->seqno += 0x10; hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); hdr->seq_ctrl |= cpu_to_le16(intf->seqno); - spin_unlock(&intf->lock); + spin_unlock_irqrestore(&intf->seqlock, irqflags); __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); } -- cgit v1.2.3 From 3b72b01d3ab623c296df49f2d71d40a38bcfb4b3 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 29 Jul 2008 13:50:39 -0400 Subject: libertas: only enable rtap with mesh firmware Since only mesh-enabled firmware has the CMD_802_11_MONITOR_MODE on which the rtap functionality depends, only expose the rtap functionality when mesh is also available. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 14d5d61cec4..bd32ac0b4e0 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -297,9 +297,7 @@ static ssize_t lbs_rtap_set(struct device *dev, lbs_add_rtap(priv); } priv->monitormode = monitor_mode; - } - - else { + } else { if (!priv->monitormode) return strlen(buf); priv->monitormode = 0; @@ -1242,8 +1240,6 @@ int lbs_start_card(struct lbs_private *priv) lbs_pr_err("cannot register ethX device\n"); goto done; } - if (device_create_file(&dev->dev, &dev_attr_lbs_rtap)) - lbs_pr_err("cannot register lbs_rtap attribute\n"); lbs_update_channel(priv); @@ -1275,6 +1271,13 @@ int lbs_start_card(struct lbs_private *priv) if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) lbs_pr_err("cannot register lbs_mesh attribute\n"); + + /* While rtap isn't related to mesh, only mesh-enabled + * firmware implements the rtap functionality via + * CMD_802_11_MONITOR_MODE. + */ + if (device_create_file(&dev->dev, &dev_attr_lbs_rtap)) + lbs_pr_err("cannot register lbs_rtap attribute\n"); } } @@ -1306,9 +1309,9 @@ void lbs_stop_card(struct lbs_private *priv) netif_carrier_off(priv->dev); lbs_debugfs_remove_one(priv); - device_remove_file(&dev->dev, &dev_attr_lbs_rtap); if (priv->mesh_tlv) { device_remove_file(&dev->dev, &dev_attr_lbs_mesh); + device_remove_file(&dev->dev, &dev_attr_lbs_rtap); } /* Flush pending command nodes */ -- cgit v1.2.3 From bf4634afd8bb72936d2d56425ec792ca1bfa92a2 Mon Sep 17 00:00:00 2001 From: Peter Chubb Date: Thu, 31 Jul 2008 10:56:34 +1000 Subject: rt2500pci: restoring missing line In kernel version 2.6.26-rc9 my wireless LAN card worked; but in the released 2.6.26, my RaLink rt2500 card wouldn't associate. Git-bisect led me to this patch: 61486e0f68d1f8966c09b734566a187d42d65c54 rt2x00: Remove ieee80211_tx_control argument from write_tx_desc() I believe that there is a problem with that patch --- it (inadvertantly) removes an extra line of code, that used to set the DATABYTE_COUNT field. This patch reinstates that line, and with it my card works again. Signed-off-by: Peter Chubb Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index aa6dfb811c7..181a146b476 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1220,6 +1220,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len); rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); rt2x00_desc_write(txd, 0, word); } -- cgit v1.2.3 From 7dcdd073bf78bb6958bbc12a1a47754a0f3c4721 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 31 Jul 2008 19:30:48 -0500 Subject: rtl8187: Fix lockups due to concurrent access to config routine Some users of the RTL8187B have experienced difficulties since commit 49292d56352a6ab90d04c3448dd8b6106dfef2d6 that introduced the power management wext hooks. This difficulty has not made much sense until it was realized that it was possible for mac80211 to make a call to the config routine while that routine was already being executed. On this device, it is necessary to loopback the TX when changing channels. Unless this is properly restored, the device will lockup. A mutex now protects the device state, and the private data in several places. The problem was found by Herton Ronaldo Krzesinski , who also suggested this type of fix. Signed-off-by: Larry Finger Acked-by: Herton Ronaldo Krzesinski Acked-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187.h | 4 ++++ drivers/net/wireless/rtl8187_dev.c | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index 1b0d750f662..5a9515c9996 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -94,6 +94,10 @@ struct rtl8187_priv { const struct rtl818x_rf_ops *rf; struct ieee80211_vif *vif; int mode; + /* The mutex protects the TX loopback state. + * Any attempt to set channels concurrently locks the device. + */ + struct mutex conf_mutex; /* rtl8187 specific */ struct ieee80211_channel channels[14]; diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 461aa26164c..57376fb993e 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -728,6 +728,7 @@ static int rtl8187_start(struct ieee80211_hw *dev) if (ret) return ret; + mutex_lock(&priv->conf_mutex); if (priv->is_rtl8187b) { reg = RTL818X_RX_CONF_MGMT | RTL818X_RX_CONF_DATA | @@ -749,6 +750,7 @@ static int rtl8187_start(struct ieee80211_hw *dev) (7 << 0 /* long retry limit */) | (7 << 21 /* MAX TX DMA */)); rtl8187_init_urbs(dev); + mutex_unlock(&priv->conf_mutex); return 0; } @@ -792,6 +794,7 @@ static int rtl8187_start(struct ieee80211_hw *dev) reg |= RTL818X_CMD_TX_ENABLE; reg |= RTL818X_CMD_RX_ENABLE; rtl818x_iowrite8(priv, &priv->map->CMD, reg); + mutex_unlock(&priv->conf_mutex); return 0; } @@ -803,6 +806,7 @@ static void rtl8187_stop(struct ieee80211_hw *dev) struct sk_buff *skb; u32 reg; + mutex_lock(&priv->conf_mutex); rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); reg = rtl818x_ioread8(priv, &priv->map->CMD); @@ -822,7 +826,7 @@ static void rtl8187_stop(struct ieee80211_hw *dev) usb_kill_urb(info->urb); kfree_skb(skb); } - return; + mutex_unlock(&priv->conf_mutex); } static int rtl8187_add_interface(struct ieee80211_hw *dev, @@ -842,6 +846,7 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev, return -EOPNOTSUPP; } + mutex_lock(&priv->conf_mutex); priv->vif = conf->vif; rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); @@ -850,6 +855,7 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev, ((u8 *)conf->mac_addr)[i]); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + mutex_unlock(&priv->conf_mutex); return 0; } @@ -857,8 +863,10 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct rtl8187_priv *priv = dev->priv; + mutex_lock(&priv->conf_mutex); priv->mode = IEEE80211_IF_TYPE_MNTR; priv->vif = NULL; + mutex_unlock(&priv->conf_mutex); } static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) @@ -866,6 +874,7 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) struct rtl8187_priv *priv = dev->priv; u32 reg; + mutex_lock(&priv->conf_mutex); reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); /* Enable TX loopback on MAC level to avoid TX during channel * changes, as this has be seen to causes problems and the @@ -898,6 +907,7 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100); rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100); + mutex_unlock(&priv->conf_mutex); return 0; } @@ -909,6 +919,7 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, int i; u8 reg; + mutex_lock(&priv->conf_mutex); for (i = 0; i < ETH_ALEN; i++) rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); @@ -922,6 +933,7 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, rtl818x_iowrite8(priv, &priv->map->MSR, reg); } + mutex_unlock(&priv->conf_mutex); return 0; } @@ -1189,6 +1201,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, printk(KERN_ERR "rtl8187: Cannot register device\n"); goto err_free_dev; } + mutex_init(&priv->conf_mutex); printk(KERN_INFO "%s: hwaddr %s, %s V%d + %s\n", wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), -- cgit v1.2.3 From fb55d887c5bd9054ec069534e1ef9eb8d9a983c6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 31 Jul 2008 19:02:06 +0200 Subject: ipw2200 - Fix bad ipw_write8() macro ipw_write8() can't be used alone with a loop because of a wrong definition. CC [M] drivers/net/wireless/ipw2200.o drivers/net/wireless/ipw2200.c: In function 'ipw_ethtool_set_eeprom': drivers/net/wireless/ipw2200.c:10579: warning: array subscript is above array bounds drivers/net/wireless/ipw2200.c: In function 'ipw_load': drivers/net/wireless/ipw2200.c:2663: warning: array subscript is above array bounds Add missing do {} while (0) to fix them. Signed-off-by: Takashi Iwai Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 1acfbcd3703..9509fd2a25f 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -305,9 +305,10 @@ static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c) #define _ipw_write8(ipw, ofs, val) writeb((val), (ipw)->hw_base + (ofs)) /* 8-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ -#define ipw_write8(ipw, ofs, val) \ +#define ipw_write8(ipw, ofs, val) do { \ IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ - _ipw_write8(ipw, ofs, val) + _ipw_write8(ipw, ofs, val); \ + } while (0) /* 16-bit direct write (low 4K) */ #define _ipw_write16(ipw, ofs, val) writew((val), (ipw)->hw_base + (ofs)) -- cgit v1.2.3 From 3d0f823953e6b5aa36fc098de2d27e15da220974 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 31 Jul 2008 19:03:10 +0200 Subject: prism54 - Use offsetof() Use the standard offsetof() macro to fix a compile warning below: CC [M] drivers/net/wireless/prism54/isl_ioctl.o drivers/net/wireless/prism54/isl_ioctl.c: In function 'prism2_ioctl_set_generic_element': drivers/net/wireless/prism54/isl_ioctl.c:2658: warning: cast from pointer to integer of different size Signed-off-by: Takashi Iwai Signed-off-by: John W. Linville --- drivers/net/wireless/prism54/isl_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 97fa14e0a47..3d75a7137d3 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -2518,7 +2518,7 @@ enum { #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ -((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data)) + offsetof(struct prism2_hostapd_param, u.generic_elem.data) /* Maximum length for algorithm names (-1 for nul termination) * used in ioctl() */ -- cgit v1.2.3 From 56decd3c5758b0d776c073f65f777beb7a05ac0a Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Fri, 1 Aug 2008 12:54:27 +0300 Subject: iwl3945: Fix statistics in monitor mode iwl3945_rx_reply_rx was sending packets too early to mac80211, before updating signal strength/quality. This resulted in garbage power levels. Signed-off-by: Maxim Levitsky Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index a51e0eaa133..56a9361a847 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -710,10 +710,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, return; } - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { - iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status); - return; - } + /* Convert 3945's rssi indicator to dBm */ rx_status.signal = rx_stats->rssi - IWL_RSSI_OFFSET; @@ -775,6 +772,11 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, priv->last_rx_noise = rx_status.noise; } + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { + iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status); + return; + } + switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) { case IEEE80211_FTYPE_MGMT: switch (le16_to_cpu(header->frame_control) & -- cgit v1.2.3 From 26a8ef5326e390d89290822fb1f4fcf16845fd84 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 31 Jul 2008 16:24:19 +0900 Subject: net: stnic: Fix up fallout from SH header migration. asm/se.h moved to mach-se/mach/se.h, update the path. We could use mach/se.h here also, but it's preferable to be explicit when there's only a single supported mach-type. Signed-off-by: Paul Mundt --- drivers/net/stnic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/stnic.c b/drivers/net/stnic.c index b65be5d70fe..2ed0bd59681 100644 --- a/drivers/net/stnic.c +++ b/drivers/net/stnic.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include #ifdef CONFIG_SH_STANDARD_BIOS #include -- cgit v1.2.3 From 61a2d07d3fb1ac34d142b9b62d4cd60a0f8c229e Mon Sep 17 00:00:00 2001 From: Niels de Vos Date: Thu, 31 Jul 2008 00:07:23 -0700 Subject: Remove newline from the description of module parameters Some module parameters with only one line have the '\n' at the end of the description. This is not needed nor wanted as after the description the type (i.e. int) is followed by a newline. Some modules contain a multi-line description, these are not affected by this patch. Signed-off-by: Niels de Vos Acked-by: Randy Dunlap Cc: John W. Linville Cc: Ed L. Cashin Cc: Dave Airlie Cc: Roland Dreier Acked-by: Mauro Carvalho Chehab Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/acpi/asus_acpi.c | 4 ++-- drivers/block/aoe/aoenet.c | 2 +- drivers/gpu/drm/radeon/radeon_drv.c | 2 +- drivers/infiniband/hw/ipath/ipath_iba7220.c | 2 +- drivers/media/video/cs5345.c | 2 +- drivers/media/video/cs53l32a.c | 2 +- drivers/media/video/mt9v022.c | 2 +- drivers/net/netconsole.c | 2 +- drivers/net/tokenring/3c359.c | 8 ++++---- drivers/net/wireless/ipw2200.c | 2 +- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/video/matrox/matroxfb_base.c | 2 +- 12 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index 44ad90c03c2..d3d0886d637 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -78,9 +78,9 @@ MODULE_LICENSE("GPL"); static uid_t asus_uid; static gid_t asus_gid; module_param(asus_uid, uint, 0); -MODULE_PARM_DESC(asus_uid, "UID for entries in /proc/acpi/asus.\n"); +MODULE_PARM_DESC(asus_uid, "UID for entries in /proc/acpi/asus"); module_param(asus_gid, uint, 0); -MODULE_PARM_DESC(asus_gid, "GID for entries in /proc/acpi/asus.\n"); +MODULE_PARM_DESC(asus_gid, "GID for entries in /proc/acpi/asus"); /* For each model, all features implemented, * those marked with R are relative to HOTK, A for absolute */ diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index d625169c8e4..0c81ca73128 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -30,7 +30,7 @@ enum { static char aoe_iflist[IFLISTSZ]; module_param_string(aoe_iflist, aoe_iflist, IFLISTSZ, 0600); -MODULE_PARM_DESC(aoe_iflist, "aoe_iflist=\"dev1 [dev2 ...]\"\n"); +MODULE_PARM_DESC(aoe_iflist, "aoe_iflist=\"dev1 [dev2 ...]\""); #ifndef MODULE static int __init aoe_iflist_setup(char *str) diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 349ac3d3b84..637bd7faf13 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -38,7 +38,7 @@ int radeon_no_wb; -MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers\n"); +MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); static int dri_library_name(struct drm_device *dev, char *buf) diff --git a/drivers/infiniband/hw/ipath/ipath_iba7220.c b/drivers/infiniband/hw/ipath/ipath_iba7220.c index fb70712ac85..fadbfbf55a6 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba7220.c +++ b/drivers/infiniband/hw/ipath/ipath_iba7220.c @@ -528,7 +528,7 @@ static const struct ipath_cregs ipath_7220_cregs = { static char int_type[16] = "auto"; module_param_string(interrupt_type, int_type, sizeof(int_type), 0444); -MODULE_PARM_DESC(int_type, " interrupt_type=auto|force_msi|force_intx\n"); +MODULE_PARM_DESC(int_type, " interrupt_type=auto|force_msi|force_intx"); /* packet rate matching delay; chip has support */ static u8 rate_to_delay[2][2] = { diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c index 61d14d26686..a662b15d5b9 100644 --- a/drivers/media/video/cs5345.c +++ b/drivers/media/video/cs5345.c @@ -35,7 +35,7 @@ static int debug; module_param(debug, bool, 0644); -MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On"); +MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On"); /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index e30a589c0e1..c4444500b33 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c @@ -39,7 +39,7 @@ static int debug; module_param(debug, bool, 0644); -MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On"); +MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On"); static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END }; diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index b31ba4e0932..56808cd2f8a 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -25,7 +25,7 @@ static char *sensor_type; module_param(sensor_type, charp, S_IRUGO); -MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"\n"); +MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); /* mt9v022 selected register addresses */ #define MT9V022_CHIP_VERSION 0x00 diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index e13966bb5f7..9681618c323 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -53,7 +53,7 @@ MODULE_LICENSE("GPL"); static char config[MAX_PARAM_LENGTH]; module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0); -MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@/[tgt-macaddr]\n"); +MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@/[tgt-macaddr]"); #ifndef MODULE static int __init option_setup(char *opt) diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 7766cde0d63..bf621328b60 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -95,20 +95,20 @@ MODULE_DESCRIPTION("3Com 3C359 Velocity XL Token Ring Adapter Driver \n") ; static int ringspeed[XL_MAX_ADAPTERS] = {0,} ; module_param_array(ringspeed, int, NULL, 0); -MODULE_PARM_DESC(ringspeed,"3c359: Ringspeed selection - 4,16 or 0") ; +MODULE_PARM_DESC(ringspeed,"3c359: Ringspeed selection - 4,16 or 0") ; /* Packet buffer size */ static int pkt_buf_sz[XL_MAX_ADAPTERS] = {0,} ; module_param_array(pkt_buf_sz, int, NULL, 0) ; -MODULE_PARM_DESC(pkt_buf_sz,"3c359: Initial buffer size") ; +MODULE_PARM_DESC(pkt_buf_sz,"3c359: Initial buffer size") ; /* Message Level */ -static int message_level[XL_MAX_ADAPTERS] = {0,} ; +static int message_level[XL_MAX_ADAPTERS] = {0,} ; module_param_array(message_level, int, NULL, 0) ; -MODULE_PARM_DESC(message_level, "3c359: Level of reported messages \n") ; +MODULE_PARM_DESC(message_level, "3c359: Level of reported messages") ; /* * This is a real nasty way of doing this, but otherwise you * will be stuck with 1555 lines of hex #'s in the code. diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 1acfbcd3703..846a7d05185 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -11946,7 +11946,7 @@ module_param(auto_create, int, 0444); MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)"); module_param(led, int, 0444); -MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)\n"); +MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)"); module_param(debug, int, 0444); MODULE_PARM_DESC(debug, "debug output mask"); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 9afecb81371..ba2df1ba32d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2469,7 +2469,7 @@ MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); module_param_named(disable, iwl4965_mod_params.disable, int, 0444); MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444); -MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])\n"); +MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); module_param_named(debug, iwl4965_mod_params.debug, int, 0444); MODULE_PARM_DESC(debug, "debug output mask"); module_param_named( diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 54e82f35353..c0213620279 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -2536,7 +2536,7 @@ module_param(fh, int, 0); MODULE_PARM_DESC(fh, "Startup horizontal frequency, 0-999kHz, 1000-INF Hz"); module_param(fv, int, 0); MODULE_PARM_DESC(fv, "Startup vertical frequency, 0-INF Hz\n" -"You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\"\n"); +"You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\""); module_param(grayscale, int, 0); MODULE_PARM_DESC(grayscale, "Sets display into grayscale. Works perfectly with paletized videomode (4, 8bpp), some limitations apply to 16, 24 and 32bpp videomodes (default=nograyscale)"); module_param(cross4MB, int, 0); -- cgit v1.2.3 From ea44c1d60df3640bd956a67c392865c44fe9bc45 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 31 Jul 2008 00:07:27 -0700 Subject: PNP: fix formatting of dbg_pnp_show_resources() output Each resource should be printed on its own line, so start snprintf'ing at the beginning of the buffer every time through the loop. Also, use scnprintf() rather than snprintf() when building up the buffer to print. scnprintf() returns the number of characters actually written into the buffer (not including the trailing NULL). snprintf() returns the number of characters that *would be* written, assuming everything would fit in the buffer. That's nice if we want to resize the buffer to make sure everything fits, but in this case, I just want to keep from overflowing the buffer, and it's OK if the output is truncated. Using snprintf() meant that my "len" could grow to be more than the the buffer size, which makes "sizeof(buf) - len" negative, which causes this alarming WARN_ON: http://marc.info/?l=linux-kernel&m=121736480005656&w=2 More useful snprintf/scnprintf discussion: http://lwn.net/Articles/69419/ Signed-off-by: Bjorn Helgaas Reported-by: Pete Clements Cc: Rene Herman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pnp/support.c | 96 ++++++++++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c index bbf78ef4ba0..b42df162071 100644 --- a/drivers/pnp/support.c +++ b/drivers/pnp/support.c @@ -77,7 +77,7 @@ void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc) { #ifdef DEBUG char buf[128]; - int len = 0; + int len; struct pnp_resource *pnp_res; struct resource *res; @@ -89,9 +89,10 @@ void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc) dev_dbg(&dev->dev, "%s: current resources:\n", desc); list_for_each_entry(pnp_res, &dev->resources, list) { res = &pnp_res->res; + len = 0; - len += snprintf(buf + len, sizeof(buf) - len, " %-3s ", - pnp_resource_type_name(res)); + len += scnprintf(buf + len, sizeof(buf) - len, " %-3s ", + pnp_resource_type_name(res)); if (res->flags & IORESOURCE_DISABLED) { dev_dbg(&dev->dev, "%sdisabled\n", buf); @@ -101,18 +102,18 @@ void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc) switch (pnp_resource_type(res)) { case IORESOURCE_IO: case IORESOURCE_MEM: - len += snprintf(buf + len, sizeof(buf) - len, - "%#llx-%#llx flags %#lx", - (unsigned long long) res->start, - (unsigned long long) res->end, - res->flags); + len += scnprintf(buf + len, sizeof(buf) - len, + "%#llx-%#llx flags %#lx", + (unsigned long long) res->start, + (unsigned long long) res->end, + res->flags); break; case IORESOURCE_IRQ: case IORESOURCE_DMA: - len += snprintf(buf + len, sizeof(buf) - len, - "%lld flags %#lx", - (unsigned long long) res->start, - res->flags); + len += scnprintf(buf + len, sizeof(buf) - len, + "%lld flags %#lx", + (unsigned long long) res->start, + res->flags); break; } dev_dbg(&dev->dev, "%s\n", buf); @@ -144,66 +145,67 @@ void dbg_pnp_show_option(struct pnp_dev *dev, struct pnp_option *option) struct pnp_dma *dma; if (pnp_option_is_dependent(option)) - len += snprintf(buf + len, sizeof(buf) - len, - " dependent set %d (%s) ", - pnp_option_set(option), - pnp_option_priority_name(option)); + len += scnprintf(buf + len, sizeof(buf) - len, + " dependent set %d (%s) ", + pnp_option_set(option), + pnp_option_priority_name(option)); else - len += snprintf(buf + len, sizeof(buf) - len, " independent "); + len += scnprintf(buf + len, sizeof(buf) - len, + " independent "); switch (option->type) { case IORESOURCE_IO: port = &option->u.port; - len += snprintf(buf + len, sizeof(buf) - len, "io min %#llx " - "max %#llx align %lld size %lld flags %#x", - (unsigned long long) port->min, - (unsigned long long) port->max, - (unsigned long long) port->align, - (unsigned long long) port->size, port->flags); + len += scnprintf(buf + len, sizeof(buf) - len, "io min %#llx " + "max %#llx align %lld size %lld flags %#x", + (unsigned long long) port->min, + (unsigned long long) port->max, + (unsigned long long) port->align, + (unsigned long long) port->size, port->flags); break; case IORESOURCE_MEM: mem = &option->u.mem; - len += snprintf(buf + len, sizeof(buf) - len, "mem min %#llx " - "max %#llx align %lld size %lld flags %#x", - (unsigned long long) mem->min, - (unsigned long long) mem->max, - (unsigned long long) mem->align, - (unsigned long long) mem->size, mem->flags); + len += scnprintf(buf + len, sizeof(buf) - len, "mem min %#llx " + "max %#llx align %lld size %lld flags %#x", + (unsigned long long) mem->min, + (unsigned long long) mem->max, + (unsigned long long) mem->align, + (unsigned long long) mem->size, mem->flags); break; case IORESOURCE_IRQ: irq = &option->u.irq; - len += snprintf(buf + len, sizeof(buf) - len, "irq"); + len += scnprintf(buf + len, sizeof(buf) - len, "irq"); if (bitmap_empty(irq->map.bits, PNP_IRQ_NR)) - len += snprintf(buf + len, sizeof(buf) - len, - " "); + len += scnprintf(buf + len, sizeof(buf) - len, + " "); else { for (i = 0; i < PNP_IRQ_NR; i++) if (test_bit(i, irq->map.bits)) - len += snprintf(buf + len, - sizeof(buf) - len, - " %d", i); + len += scnprintf(buf + len, + sizeof(buf) - len, + " %d", i); } - len += snprintf(buf + len, sizeof(buf) - len, " flags %#x", - irq->flags); + len += scnprintf(buf + len, sizeof(buf) - len, " flags %#x", + irq->flags); if (irq->flags & IORESOURCE_IRQ_OPTIONAL) - len += snprintf(buf + len, sizeof(buf) - len, - " (optional)"); + len += scnprintf(buf + len, sizeof(buf) - len, + " (optional)"); break; case IORESOURCE_DMA: dma = &option->u.dma; - len += snprintf(buf + len, sizeof(buf) - len, "dma"); + len += scnprintf(buf + len, sizeof(buf) - len, "dma"); if (!dma->map) - len += snprintf(buf + len, sizeof(buf) - len, - " "); + len += scnprintf(buf + len, sizeof(buf) - len, + " "); else { for (i = 0; i < 8; i++) if (dma->map & (1 << i)) - len += snprintf(buf + len, - sizeof(buf) - len, - " %d", i); + len += scnprintf(buf + len, + sizeof(buf) - len, + " %d", i); } - len += snprintf(buf + len, sizeof(buf) - len, " (bitmask %#x) " - "flags %#x", dma->map, dma->flags); + len += scnprintf(buf + len, sizeof(buf) - len, " (bitmask %#x) " + "flags %#x", dma->map, dma->flags); break; } dev_dbg(&dev->dev, "%s\n", buf); -- cgit v1.2.3 From 3ab36ab68531ad90648fdeedcaf437f121572ede Mon Sep 17 00:00:00 2001 From: Eugeniy Meshcheryakov Date: Thu, 31 Jul 2008 10:03:19 +0100 Subject: try harder to load tty ldisc driver Currently function tty_ldisc_get() tries to load an ldisc driver module only when tty_ldisc_try_get() returns -EAGAIN. This happens only if module is being unloaded. If ldisc module is not loaded tty_ldisc_try_get() returns -EINVAL and this case is not handled in tty_ldisc_get(), so request_module() is not called. Attached patch fixes this by calling request_module() if tty_ldisc_try_get() returned any error code. I discovered this when my UMTS modem stopped working with 2.6.27-rc1 because module ppp_async was not loaded. Signed-off-by: Eugeniy Meshcheryakov Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/char/tty_ldisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index 241cbdea65a..f307f135cbf 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c @@ -169,7 +169,7 @@ static int tty_ldisc_get(int disc, struct tty_ldisc *ld) if (disc < N_TTY || disc >= NR_LDISCS) return -EINVAL; err = tty_ldisc_try_get(disc, ld); - if (err == -EAGAIN) { + if (err < 0) { request_module("tty-ldisc-%d", disc); err = tty_ldisc_try_get(disc, ld); } -- cgit v1.2.3 From f1136d022af8f07a97f59c6d07483bdb82ffbd8e Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 2 Aug 2008 00:01:21 +0100 Subject: [MTD] Fix !CONFIG_BLOCK compile for mtdsuper.c As reported by Adrian Bunk, commit d5686b444ff3f72808d2b3fbd58672a86cdf38e7 (switch mtd and dm-table to lookup_bdev()) causes the following compile error with CONFIG_BLOCK=n: CC drivers/mtd/mtdsuper.o drivers/mtd/mtdsuper.c: In function `get_sb_mtd': drivers/mtd/mtdsuper.c:184: error: implicit declaration of function 'lookup_bdev' drivers/mtd/mtdsuper.c:184: warning: assignment makes pointer from integer without a cast drivers/mtd/mtdsuper.c:197: error: implicit declaration of function 'bdput' make[3]: *** [drivers/mtd/mtdsuper.o] Error 1 Fix it by putting the block device lookup inside #ifdef CONFIG_BLOCK Signed-off-by: David Woodhouse --- drivers/mtd/mtdsuper.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c index 9b6af7e74a6..00d46e137b2 100644 --- a/drivers/mtd/mtdsuper.c +++ b/drivers/mtd/mtdsuper.c @@ -125,8 +125,11 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, int (*fill_super)(struct super_block *, void *, int), struct vfsmount *mnt) { +#ifdef CONFIG_BLOCK struct block_device *bdev; - int mtdnr, ret; + int ret, major; +#endif + int mtdnr; if (!dev_name) return -EINVAL; @@ -178,6 +181,7 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, } } +#ifdef CONFIG_BLOCK /* try the old way - the hack where we allowed users to mount * /dev/mtdblock$(n) but didn't actually _use_ the blockdev */ @@ -190,22 +194,25 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, DEBUG(1, "MTDSB: lookup_bdev() returned 0\n"); ret = -EINVAL; - if (MAJOR(bdev->bd_dev) != MTD_BLOCK_MAJOR) - goto not_an_MTD_device; + major = MAJOR(bdev->bd_dev); mtdnr = MINOR(bdev->bd_dev); bdput(bdev); + if (major != MTD_BLOCK_MAJOR) + goto not_an_MTD_device; + return get_sb_mtd_nr(fs_type, flags, dev_name, data, mtdnr, fill_super, mnt); not_an_MTD_device: +#endif /* CONFIG_BLOCK */ + if (!(flags & MS_SILENT)) printk(KERN_NOTICE "MTD: Attempt to mount non-MTD device \"%s\"\n", dev_name); - bdput(bdev); - return ret; + return -EINVAL; } EXPORT_SYMBOL_GPL(get_sb_mtd); -- cgit v1.2.3 From 82f97b8d3cb3982ec97e081598c671fab2c321b0 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 2 Aug 2008 01:31:09 -0700 Subject: rt2x00: Fix compile warning rt2x00usb_vendor_request_large_buff is write-only, so it is safe to make the argument a const. Fixes compile warning: drivers/net/wireless/rt2x00/rt73usb.c: In function 'rt73usb_load_firmware': drivers/net/wireless/rt2x00/rt73usb.c:916: warning: passing argument 5 of 'rt2x00usb_vendor_request_large_buff' discards qualifiers from pointer target typ Signed-off-by: Ivo van Doorn Signed-off-by: David S. Miller --- drivers/net/wireless/rt2x00/rt2x00usb.c | 4 ++-- drivers/net/wireless/rt2x00/rt2x00usb.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 933e6cc9359..8d76bb2e031 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -124,7 +124,7 @@ EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff); int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev, const u8 request, const u8 requesttype, - const u16 offset, void *buffer, + const u16 offset, const void *buffer, const u16 buffer_length, const int timeout) { @@ -134,7 +134,7 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev, mutex_lock(&rt2x00dev->usb_cache_mutex); - tb = buffer; + tb = (char *)buffer; off = offset; len = buffer_length; while (len && !status) { diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index ee3875f894a..3b4a67417f9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -185,7 +185,7 @@ int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev, */ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev, const u8 request, const u8 requesttype, - const u16 offset, void *buffer, + const u16 offset, const void *buffer, const u16 buffer_length, const int timeout); -- cgit v1.2.3 From 780aefed1e179b23dcfbd6cfcb627ec3bd0a164c Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Tue, 29 Jul 2008 18:47:22 +0200 Subject: mISDN fix main ISDN Makefile Compile hardware directory independent from selecting CAPI support. Signed-off-by: Karsten Keil --- drivers/isdn/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile index 8380a4568d1..f1f777570e8 100644 --- a/drivers/isdn/Makefile +++ b/drivers/isdn/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_ISDN_I4L) += i4l/ obj-$(CONFIG_ISDN_CAPI) += capi/ obj-$(CONFIG_MISDN) += mISDN/ -obj-$(CONFIG_ISDN_CAPI) += hardware/ +obj-$(CONFIG_ISDN) += hardware/ obj-$(CONFIG_ISDN_DIVERSION) += divert/ obj-$(CONFIG_ISDN_DRV_HISAX) += hisax/ obj-$(CONFIG_ISDN_DRV_ICN) += icn/ -- cgit v1.2.3 From ff4cc1de2401ad44ae084c3f5a9e898af0879520 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Wed, 30 Jul 2008 18:26:58 +0200 Subject: mISDN cleanup user interface The channelmap should have the same size on 32 and 64 bit systems and should not depend on endianess. Thanks to David Woodhouse for spotting this. Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/hfcmulti.c | 6 +++--- drivers/isdn/hardware/mISDN/hfcpci.c | 2 +- drivers/isdn/mISDN/l1oip_core.c | 6 ++---- drivers/isdn/mISDN/socket.c | 4 ++-- 4 files changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 2649ea55a9e..10144e871c0 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -3971,7 +3971,7 @@ open_bchannel(struct hfc_multi *hc, struct dchannel *dch, struct bchannel *bch; int ch; - if (!test_bit(rq->adr.channel, &dch->dev.channelmap[0])) + if (!test_channelmap(rq->adr.channel, dch->dev.channelmap)) return -EINVAL; if (rq->protocol == ISDN_P_NONE) return -EINVAL; @@ -4587,7 +4587,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) list_add(&bch->ch.list, &dch->dev.bchannels); hc->chan[ch].bch = bch; hc->chan[ch].port = 0; - test_and_set_bit(bch->nr, &dch->dev.channelmap[0]); + set_channelmap(bch->nr, dch->dev.channelmap); } /* set optical line type */ if (port[Port_cnt] & 0x001) { @@ -4755,7 +4755,7 @@ init_multi_port(struct hfc_multi *hc, int pt) list_add(&bch->ch.list, &dch->dev.bchannels); hc->chan[i + ch].bch = bch; hc->chan[i + ch].port = pt; - test_and_set_bit(bch->nr, &dch->dev.channelmap[0]); + set_channelmap(bch->nr, dch->dev.channelmap); } /* set master clock */ if (port[Port_cnt] & 0x001) { diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 3231814e7ef..9cf5edbb1a9 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -2056,7 +2056,7 @@ setup_card(struct hfc_pci *card) card->dch.dev.nrbchan = 2; for (i = 0; i < 2; i++) { card->bch[i].nr = i + 1; - test_and_set_bit(i + 1, &card->dch.dev.channelmap[0]); + set_channelmap(i + 1, card->dch.dev.channelmap); card->bch[i].debug = debug; mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM); card->bch[i].hw = card; diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index 155b99780c4..e42150a5778 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -1006,8 +1006,7 @@ open_bchannel(struct l1oip *hc, struct dchannel *dch, struct channel_req *rq) struct bchannel *bch; int ch; - if (!test_bit(rq->adr.channel & 0x1f, - &dch->dev.channelmap[rq->adr.channel >> 5])) + if (!test_channelmap(rq->adr.channel, dch->dev.channelmap)) return -EINVAL; if (rq->protocol == ISDN_P_NONE) return -EINVAL; @@ -1412,8 +1411,7 @@ init_card(struct l1oip *hc, int pri, int bundle) bch->ch.nr = i + ch; list_add(&bch->ch.list, &dch->dev.bchannels); hc->chan[i + ch].bch = bch; - test_and_set_bit(bch->nr & 0x1f, - &dch->dev.channelmap[bch->nr >> 5]); + set_channelmap(bch->nr, dch->dev.channelmap); } ret = mISDN_register_device(&dch->dev, hc->name); if (ret) diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 4ba4cc364c9..e5a20f9542d 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -379,7 +379,7 @@ data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) di.Bprotocols = dev->Bprotocols | get_all_Bprotocols(); di.protocol = dev->D.protocol; memcpy(di.channelmap, dev->channelmap, - MISDN_CHMAP_SIZE * 4); + sizeof(di.channelmap)); di.nrbchan = dev->nrbchan; strcpy(di.name, dev->name); if (copy_to_user((void __user *)arg, &di, sizeof(di))) @@ -637,7 +637,7 @@ base_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) di.Bprotocols = dev->Bprotocols | get_all_Bprotocols(); di.protocol = dev->D.protocol; memcpy(di.channelmap, dev->channelmap, - MISDN_CHMAP_SIZE * 4); + sizeof(di.channelmap)); di.nrbchan = dev->nrbchan; strcpy(di.name, dev->name); if (copy_to_user((void __user *)arg, &di, sizeof(di))) -- cgit v1.2.3 From b3e0aeeb7e0f89791c4c3bdfd98b36074c5178e6 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Sat, 2 Aug 2008 16:35:53 +0200 Subject: Fix remaining big endian issue of hfcmulti The driver was not so bad at big endian at all, only the optimised fifo read/write functions need a fix, with this fix the driver works on a pegasus PPC machine. Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/hfcmulti.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 10144e871c0..e36360a583d 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -140,7 +140,7 @@ * #define HFC_REGISTER_DEBUG */ -static const char *hfcmulti_revision = "2.00"; +static const char *hfcmulti_revision = "2.01"; #include #include @@ -427,12 +427,12 @@ write_fifo_regio(struct hfc_multi *hc, u_char *data, int len) { outb(A_FIFO_DATA0, (hc->pci_iobase)+4); while (len>>2) { - outl(*(u32 *)data, hc->pci_iobase); + outl(cpu_to_le32(*(u32 *)data), hc->pci_iobase); data += 4; len -= 4; } while (len>>1) { - outw(*(u16 *)data, hc->pci_iobase); + outw(cpu_to_le16(*(u16 *)data), hc->pci_iobase); data += 2; len -= 2; } @@ -447,17 +447,19 @@ void write_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) { while (len>>2) { - writel(*(u32 *)data, (hc->pci_membase)+A_FIFO_DATA0); + writel(cpu_to_le32(*(u32 *)data), + hc->pci_membase + A_FIFO_DATA0); data += 4; len -= 4; } while (len>>1) { - writew(*(u16 *)data, (hc->pci_membase)+A_FIFO_DATA0); + writew(cpu_to_le16(*(u16 *)data), + hc->pci_membase + A_FIFO_DATA0); data += 2; len -= 2; } while (len) { - writeb(*data, (hc->pci_membase)+A_FIFO_DATA0); + writeb(*data, hc->pci_membase + A_FIFO_DATA0); data++; len--; } @@ -468,12 +470,12 @@ read_fifo_regio(struct hfc_multi *hc, u_char *data, int len) { outb(A_FIFO_DATA0, (hc->pci_iobase)+4); while (len>>2) { - *(u32 *)data = inl(hc->pci_iobase); + *(u32 *)data = le32_to_cpu(inl(hc->pci_iobase)); data += 4; len -= 4; } while (len>>1) { - *(u16 *)data = inw(hc->pci_iobase); + *(u16 *)data = le16_to_cpu(inw(hc->pci_iobase)); data += 2; len -= 2; } @@ -490,18 +492,18 @@ read_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) { while (len>>2) { *(u32 *)data = - readl((hc->pci_membase)+A_FIFO_DATA0); + le32_to_cpu(readl(hc->pci_membase + A_FIFO_DATA0)); data += 4; len -= 4; } while (len>>1) { *(u16 *)data = - readw((hc->pci_membase)+A_FIFO_DATA0); + le16_to_cpu(readw(hc->pci_membase + A_FIFO_DATA0)); data += 2; len -= 2; } while (len) { - *data = readb((hc->pci_membase)+A_FIFO_DATA0); + *data = readb(hc->pci_membase + A_FIFO_DATA0); data++; len--; } @@ -5251,9 +5253,6 @@ HFCmulti_init(void) if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: init entered\n", __func__); -#ifdef __BIG_ENDIAN -#error "not running on big endian machines now" -#endif hfc_interrupt = symbol_get(ztdummy_extern_interrupt); register_interrupt = symbol_get(ztdummy_register_interrupt); unregister_interrupt = symbol_get(ztdummy_unregister_interrupt); -- cgit v1.2.3 From 31981db0d0b665713ab3e9531f936fdb67947225 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Sat, 2 Aug 2008 16:40:37 +0200 Subject: Add DIP switch readout for HFC-4S IOB4ST Also the HFC-4S IOB4ST has DIP switches and jumpers to configure the port. Signed-off-by: Karsten Keil --- drivers/isdn/hardware/mISDN/hfcmulti.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index e36360a583d..1eac03f39d0 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -140,7 +140,7 @@ * #define HFC_REGISTER_DEBUG */ -static const char *hfcmulti_revision = "2.01"; +static const char *hfcmulti_revision = "2.02"; #include #include @@ -5052,12 +5052,12 @@ static void __devexit hfc_remove_pci(struct pci_dev *pdev) static const struct hm_map hfcm_map[] = { /*0*/ {VENDOR_BN, "HFC-1S Card (mini PCI)", 4, 1, 1, 3, 0, DIP_4S, 0}, -/*1*/ {VENDOR_BN, "HFC-2S Card", 4, 2, 1, 3, 0, DIP_4S}, +/*1*/ {VENDOR_BN, "HFC-2S Card", 4, 2, 1, 3, 0, DIP_4S, 0}, /*2*/ {VENDOR_BN, "HFC-2S Card (mini PCI)", 4, 2, 1, 3, 0, DIP_4S, 0}, /*3*/ {VENDOR_BN, "HFC-4S Card", 4, 4, 1, 2, 0, DIP_4S, 0}, /*4*/ {VENDOR_BN, "HFC-4S Card (mini PCI)", 4, 4, 1, 2, 0, 0, 0}, /*5*/ {VENDOR_CCD, "HFC-4S Eval (old)", 4, 4, 0, 0, 0, 0, 0}, -/*6*/ {VENDOR_CCD, "HFC-4S IOB4ST", 4, 4, 1, 2, 0, 0, 0}, +/*6*/ {VENDOR_CCD, "HFC-4S IOB4ST", 4, 4, 1, 2, 0, DIP_4S, 0}, /*7*/ {VENDOR_CCD, "HFC-4S", 4, 4, 1, 2, 0, 0, 0}, /*8*/ {VENDOR_DIG, "HFC-4S Card", 4, 4, 0, 2, 0, 0, HFC_IO_MODE_REGIO}, /*9*/ {VENDOR_CCD, "HFC-4S Swyx 4xS0 SX2 QuadBri", 4, 4, 1, 2, 0, 0, 0}, -- cgit v1.2.3 From 86d9d32c7b17f8145dc8cbc9667e6385bf8ebc67 Mon Sep 17 00:00:00 2001 From: Adrian McMenamin Date: Wed, 30 Jul 2008 12:31:38 -0700 Subject: maple: allow removal and reinsertion of keyboard driver module Allow the removal (and subsequent reinsertion) of the maple_keyb (maple keyboard) driver by adding a working removal function. Also tidy long lines. Signed-off-by: Adrian McMenamin Cc: Dmitry Torokhov Cc: Paul Mundt Signed-off-by: Andrew Morton Signed-off-by: Paul Mundt --- drivers/input/keyboard/maple_keyb.c | 124 +++++++++++++++++++++++------------- 1 file changed, 81 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c index 7797ef6e5e6..7d13f55b504 100644 --- a/drivers/input/keyboard/maple_keyb.c +++ b/drivers/input/keyboard/maple_keyb.c @@ -2,7 +2,7 @@ * SEGA Dreamcast keyboard driver * Based on drivers/usb/usbkbd.c * Copyright YAEGASHI Takeshi, 2001 - * Porting to 2.6 Copyright Adrian McMenamin, 2007 + * Porting to 2.6 Copyright Adrian McMenamin, 2007, 2008 * * 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 @@ -45,39 +45,51 @@ struct dc_kbd { }; static const unsigned short dc_kbd_keycode[NR_SCANCODES] = { - KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_A, KEY_B, KEY_C, KEY_D, - KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, - KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, - KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_1, KEY_2, - KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, - KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE, - KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_BACKSLASH, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, - KEY_DOT, KEY_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_A, KEY_B, + KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, + KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, + KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, + KEY_7, KEY_8, KEY_9, KEY_0, KEY_ENTER, KEY_ESC, KEY_BACKSPACE, + KEY_TAB, KEY_SPACE, KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE, + KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_BACKSLASH, KEY_SEMICOLON, + KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, KEY_DOT, KEY_SLASH, + KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_SYSRQ, - KEY_SCROLLLOCK, KEY_PAUSE, KEY_INSERT, KEY_HOME, KEY_PAGEUP, KEY_DELETE, - KEY_END, KEY_PAGEDOWN, KEY_RIGHT, KEY_LEFT, KEY_DOWN, KEY_UP, - KEY_NUMLOCK, KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS, KEY_KPPLUS, KEY_KPENTER, KEY_KP1, KEY_KP2, - KEY_KP3, KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7, KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT, - KEY_102ND, KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL, KEY_F13, KEY_F14, KEY_F15, - KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20, - KEY_F21, KEY_F22, KEY_F23, KEY_F24, KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT, - KEY_STOP, KEY_AGAIN, KEY_UNDO, KEY_CUT, KEY_COPY, KEY_PASTE, KEY_FIND, KEY_MUTE, - KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_KPCOMMA, KEY_RESERVED, KEY_RO, KEY_KATAKANAHIRAGANA , KEY_YEN, - KEY_HENKAN, KEY_MUHENKAN, KEY_KPJPCOMMA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, - KEY_HANGEUL, KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA, KEY_ZENKAKUHANKAKU, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, - KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, - KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, - KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, - KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, - KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, - KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, - KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, - KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, - KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, - KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA, KEY_RIGHTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT, KEY_RIGHTMETA, - KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG, KEY_NEXTSONG, KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE, - KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP, KEY_FIND, KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_EDIT, KEY_SLEEP, - KEY_SCREENLOCK, KEY_REFRESH, KEY_CALC, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED + KEY_SCROLLLOCK, KEY_PAUSE, KEY_INSERT, KEY_HOME, KEY_PAGEUP, + KEY_DELETE, KEY_END, KEY_PAGEDOWN, KEY_RIGHT, KEY_LEFT, KEY_DOWN, + KEY_UP, KEY_NUMLOCK, KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS, + KEY_KPPLUS, KEY_KPENTER, KEY_KP1, KEY_KP2, KEY_KP3, KEY_KP4, KEY_KP5, + KEY_KP6, KEY_KP7, KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT, KEY_102ND, + KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL, KEY_F13, KEY_F14, KEY_F15, + KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20, KEY_F21, KEY_F22, + KEY_F23, KEY_F24, KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT, KEY_STOP, + KEY_AGAIN, KEY_UNDO, KEY_CUT, KEY_COPY, KEY_PASTE, KEY_FIND, KEY_MUTE, + KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_KPCOMMA, KEY_RESERVED, KEY_RO, KEY_KATAKANAHIRAGANA , KEY_YEN, + KEY_HENKAN, KEY_MUHENKAN, KEY_KPJPCOMMA, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_HANGEUL, KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA, + KEY_ZENKAKUHANKAKU, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, + KEY_LEFTMETA, KEY_RIGHTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT, + KEY_RIGHTMETA, KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG, + KEY_NEXTSONG, KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE, + KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP, KEY_FIND, KEY_SCROLLUP, + KEY_SCROLLDOWN, KEY_EDIT, KEY_SLEEP, KEY_SCREENLOCK, KEY_REFRESH, + KEY_CALC, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED }; static void dc_scan_kbd(struct dc_kbd *kbd) @@ -151,14 +163,15 @@ static int dc_kbd_connect(struct maple_device *mdev) struct dc_kbd *kbd; struct input_dev *dev; - if (!(mdev->function & MAPLE_FUNC_KEYBOARD)) - return -EINVAL; - kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL); + if (!kbd) { + error = -ENOMEM; + goto fail_kbd; + } dev = input_allocate_device(); - if (!kbd || !dev) { + if (!dev) { error = -ENOMEM; - goto fail; + goto fail_dev; } mdev->private_data = kbd; @@ -169,7 +182,7 @@ static int dc_kbd_connect(struct maple_device *mdev) dev->name = mdev->product_name; dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); dev->keycode = kbd->keycode; - dev->keycodesize = sizeof (unsigned short); + dev->keycodesize = sizeof(unsigned short); dev->keycodemax = ARRAY_SIZE(kbd->keycode); dev->id.bustype = BUS_HOST; dev->dev.parent = &mdev->dev; @@ -186,12 +199,15 @@ static int dc_kbd_connect(struct maple_device *mdev) goto fail; /* Maple polling is locked to VBLANK - which may be just 50/s */ - maple_getcond_callback(mdev, dc_kbd_callback, HZ/50, MAPLE_FUNC_KEYBOARD); + maple_getcond_callback(mdev, dc_kbd_callback, HZ/50, + MAPLE_FUNC_KEYBOARD); return 0; - fail: +fail: input_free_device(dev); +fail_dev: kfree(kbd); +fail_kbd: mdev->private_data = NULL; return error; } @@ -201,7 +217,7 @@ static void dc_kbd_disconnect(struct maple_device *mdev) struct dc_kbd *kbd; mutex_lock(&maple_keyb_mutex); - + mdev->callback = NULL; kbd = mdev->private_data; mdev->private_data = NULL; input_unregister_device(kbd->dev); @@ -222,11 +238,18 @@ static int probe_maple_kbd(struct device *dev) return error; mdev->driver = mdrv; - mdev->registered = 1; return 0; } +static int remove_maple_kbd(struct device *dev) +{ + struct maple_device *mdev = to_maple_dev(dev); + + dc_kbd_disconnect(mdev); + return 0; +} + static struct maple_driver dc_kbd_driver = { .function = MAPLE_FUNC_KEYBOARD, .connect = dc_kbd_connect, @@ -234,9 +257,23 @@ static struct maple_driver dc_kbd_driver = { .drv = { .name = "Dreamcast_keyboard", .probe = probe_maple_kbd, + .remove = remove_maple_kbd, }, }; +static int unplug_maple_keyb(struct device *dev, void *ignored) +{ + /* Please DO NOT really unplug your keyboard */ + struct maple_device *mdev; + + mdev = to_maple_dev(dev); + if ((mdev->function & MAPLE_FUNC_KEYBOARD) + && (mdev->driver == &dc_kbd_driver)) + remove_maple_kbd(dev); + + return 0; +} + static int __init dc_kbd_init(void) { return maple_driver_register(&dc_kbd_driver.drv); @@ -244,6 +281,7 @@ static int __init dc_kbd_init(void) static void __exit dc_kbd_exit(void) { + bus_for_each_dev(&maple_bus_type, NULL, NULL, unplug_maple_keyb); driver_unregister(&dc_kbd_driver.drv); } -- cgit v1.2.3 From 459021fe3627083ea6678a7b29f9f74accf9c6fd Mon Sep 17 00:00:00 2001 From: Adrian McMenamin Date: Mon, 4 Aug 2008 10:09:03 +0900 Subject: input: Clean up maple keyboard driver Have a single probe function instead of a probe and a connect function. Also tidy a comment. Signed-off-by: Adrian McMenamin Signed-off-by: Paul Mundt --- drivers/input/keyboard/maple_keyb.c | 101 ++++++++++++------------------------ 1 file changed, 32 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c index 7d13f55b504..42f5d4ec39a 100644 --- a/drivers/input/keyboard/maple_keyb.c +++ b/drivers/input/keyboard/maple_keyb.c @@ -143,8 +143,8 @@ static void dc_kbd_callback(struct mapleq *mq) unsigned long *buf = mq->recvbuf; /* - * We should always be getting the lock because the only - * time it may be locked if driver is in cleanup phase. + * We should always get the lock because the only + * time it may be locked is if the driver is in the cleanup phase. */ if (likely(mutex_trylock(&maple_keyb_mutex))) { @@ -157,103 +157,80 @@ static void dc_kbd_callback(struct mapleq *mq) } } -static int dc_kbd_connect(struct maple_device *mdev) +static int probe_maple_kbd(struct device *dev) { + struct maple_device *mdev = to_maple_dev(dev); + struct maple_driver *mdrv = to_maple_driver(dev->driver); int i, error; struct dc_kbd *kbd; - struct input_dev *dev; + struct input_dev *idev; + + if (!(mdev->function & MAPLE_FUNC_KEYBOARD)) + return -EINVAL; kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL); - if (!kbd) { + idev = input_allocate_device(); + if (!kbd || !idev) { error = -ENOMEM; - goto fail_kbd; - } - dev = input_allocate_device(); - if (!dev) { - error = -ENOMEM; - goto fail_dev; + goto fail; } mdev->private_data = kbd; - kbd->dev = dev; + kbd->dev = idev; memcpy(kbd->keycode, dc_kbd_keycode, sizeof(kbd->keycode)); - dev->name = mdev->product_name; - dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); - dev->keycode = kbd->keycode; - dev->keycodesize = sizeof(unsigned short); - dev->keycodemax = ARRAY_SIZE(kbd->keycode); - dev->id.bustype = BUS_HOST; - dev->dev.parent = &mdev->dev; + idev->name = mdev->product_name; + idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + idev->keycode = kbd->keycode; + idev->keycodesize = sizeof(unsigned short); + idev->keycodemax = ARRAY_SIZE(kbd->keycode); + idev->id.bustype = BUS_HOST; + idev->dev.parent = &mdev->dev; for (i = 0; i < NR_SCANCODES; i++) - __set_bit(dc_kbd_keycode[i], dev->keybit); - __clear_bit(KEY_RESERVED, dev->keybit); + __set_bit(dc_kbd_keycode[i], idev->keybit); + __clear_bit(KEY_RESERVED, idev->keybit); - input_set_capability(dev, EV_MSC, MSC_SCAN); - input_set_drvdata(dev, kbd); + input_set_capability(idev, EV_MSC, MSC_SCAN); + input_set_drvdata(idev, kbd); - error = input_register_device(dev); + error = input_register_device(idev); if (error) goto fail; /* Maple polling is locked to VBLANK - which may be just 50/s */ maple_getcond_callback(mdev, dc_kbd_callback, HZ/50, MAPLE_FUNC_KEYBOARD); - return 0; + + mdev->driver = mdrv; + return error; fail: - input_free_device(dev); -fail_dev: + input_free_device(idev); kfree(kbd); -fail_kbd: mdev->private_data = NULL; return error; } -static void dc_kbd_disconnect(struct maple_device *mdev) +static int remove_maple_kbd(struct device *dev) { + struct maple_device *mdev = to_maple_dev(dev); struct dc_kbd *kbd; mutex_lock(&maple_keyb_mutex); - mdev->callback = NULL; + kbd = mdev->private_data; mdev->private_data = NULL; input_unregister_device(kbd->dev); kfree(kbd); mutex_unlock(&maple_keyb_mutex); -} - -/* allow the keyboard to be used */ -static int probe_maple_kbd(struct device *dev) -{ - struct maple_device *mdev = to_maple_dev(dev); - struct maple_driver *mdrv = to_maple_driver(dev->driver); - int error; - - error = dc_kbd_connect(mdev); - if (error) - return error; - - mdev->driver = mdrv; - - return 0; -} - -static int remove_maple_kbd(struct device *dev) -{ - struct maple_device *mdev = to_maple_dev(dev); - - dc_kbd_disconnect(mdev); return 0; } static struct maple_driver dc_kbd_driver = { .function = MAPLE_FUNC_KEYBOARD, - .connect = dc_kbd_connect, - .disconnect = dc_kbd_disconnect, .drv = { .name = "Dreamcast_keyboard", .probe = probe_maple_kbd, @@ -261,19 +238,6 @@ static struct maple_driver dc_kbd_driver = { }, }; -static int unplug_maple_keyb(struct device *dev, void *ignored) -{ - /* Please DO NOT really unplug your keyboard */ - struct maple_device *mdev; - - mdev = to_maple_dev(dev); - if ((mdev->function & MAPLE_FUNC_KEYBOARD) - && (mdev->driver == &dc_kbd_driver)) - remove_maple_kbd(dev); - - return 0; -} - static int __init dc_kbd_init(void) { return maple_driver_register(&dc_kbd_driver.drv); @@ -281,7 +245,6 @@ static int __init dc_kbd_init(void) static void __exit dc_kbd_exit(void) { - bus_for_each_dev(&maple_bus_type, NULL, NULL, unplug_maple_keyb); driver_unregister(&dc_kbd_driver.drv); } -- cgit v1.2.3 From 63870295de9adb365cd121dab94379b8cfdf986a Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 4 Aug 2008 10:39:46 +0900 Subject: maple: Clean up maple_driver_register/unregister routines. These were completely inconsistent. Clean these up to take a maple_driver pointer directly for consistency. Signed-off-by: Paul Mundt --- drivers/input/keyboard/maple_keyb.c | 6 +++--- drivers/sh/maple/maple.c | 37 ++++++++++++++++++++++++++----------- 2 files changed, 29 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c index 42f5d4ec39a..3f5151a0fd1 100644 --- a/drivers/input/keyboard/maple_keyb.c +++ b/drivers/input/keyboard/maple_keyb.c @@ -235,17 +235,17 @@ static struct maple_driver dc_kbd_driver = { .name = "Dreamcast_keyboard", .probe = probe_maple_kbd, .remove = remove_maple_kbd, - }, + }, }; static int __init dc_kbd_init(void) { - return maple_driver_register(&dc_kbd_driver.drv); + return maple_driver_register(&dc_kbd_driver); } static void __exit dc_kbd_exit(void) { - driver_unregister(&dc_kbd_driver.drv); + maple_driver_unregister(&dc_kbd_driver); } module_init(dc_kbd_init); diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c index be97789fa5f..a6b4dc3cfcb 100644 --- a/drivers/sh/maple/maple.c +++ b/drivers/sh/maple/maple.c @@ -2,6 +2,7 @@ * Core maple bus functionality * * Copyright (C) 2007, 2008 Adrian McMenamin + * Copyright (C) 2001 - 2008 Paul Mundt * * Based on 2.4 code by: * @@ -31,7 +32,7 @@ #include #include -MODULE_AUTHOR("Yaegshi Takeshi, Paul Mundt, M.R. Brown, Adrian McMenamin"); +MODULE_AUTHOR("Yaegashi Takeshi, Paul Mundt, M. R. Brown, Adrian McMenamin"); MODULE_DESCRIPTION("Maple bus driver for Dreamcast"); MODULE_LICENSE("GPL v2"); MODULE_SUPPORTED_DEVICE("{{SEGA, Dreamcast/Maple}}"); @@ -65,19 +66,35 @@ static bool checked[4]; static struct maple_device *baseunits[4]; /** - * maple_driver_register - register a device driver - * automatically makes the driver bus a maple bus - * @drv: the driver to be registered + * maple_driver_register - register a maple driver + * @drv: maple driver to be registered. + * + * Registers the passed in @drv, while updating the bus type. + * Devices with matching function IDs will be automatically probed. */ -int maple_driver_register(struct device_driver *drv) +int maple_driver_register(struct maple_driver *drv) { if (!drv) return -EINVAL; - drv->bus = &maple_bus_type; - return driver_register(drv); + + drv->drv.bus = &maple_bus_type; + + return driver_register(&drv->drv); } EXPORT_SYMBOL_GPL(maple_driver_register); +/** + * maple_driver_unregister - unregister a maple driver. + * @drv: maple driver to unregister. + * + * Cleans up after maple_driver_register(). To be invoked in the exit + * path of any module drivers. + */ +void maple_driver_unregister(struct maple_driver *drv) +{ + driver_unregister(&drv->drv); +} + /* set hardware registers to enable next round of dma */ static void maplebus_dma_reset(void) { @@ -724,11 +741,9 @@ static int maple_get_dma_buffer(void) static int match_maple_bus_driver(struct device *devptr, struct device_driver *drvptr) { - struct maple_driver *maple_drv; - struct maple_device *maple_dev; + struct maple_driver *maple_drv = to_maple_driver(drvptr); + struct maple_device *maple_dev = to_maple_dev(devptr); - maple_drv = container_of(drvptr, struct maple_driver, drv); - maple_dev = container_of(devptr, struct maple_device, dev); /* Trap empty port case */ if (maple_dev->devinfo.function == 0xFFFFFFFF) return 0; -- cgit v1.2.3 From 617870632de6739fca0893f3e6648e9ae1bd0ddb Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 4 Aug 2008 10:58:24 +0900 Subject: maple: Kill useless private_data pointer. We can simply wrap in to the dev_set/get_drvdata(), there's no reason to track an extra level of private data on top of the struct device. Signed-off-by: Paul Mundt --- drivers/input/keyboard/maple_keyb.c | 15 ++++++++------- drivers/sh/maple/maple.c | 1 + 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c index 3f5151a0fd1..22f17a593be 100644 --- a/drivers/input/keyboard/maple_keyb.c +++ b/drivers/input/keyboard/maple_keyb.c @@ -139,7 +139,7 @@ static void dc_scan_kbd(struct dc_kbd *kbd) static void dc_kbd_callback(struct mapleq *mq) { struct maple_device *mapledev = mq->dev; - struct dc_kbd *kbd = mapledev->private_data; + struct dc_kbd *kbd = maple_get_drvdata(mapledev); unsigned long *buf = mq->recvbuf; /* @@ -175,8 +175,6 @@ static int probe_maple_kbd(struct device *dev) goto fail; } - mdev->private_data = kbd; - kbd->dev = idev; memcpy(kbd->keycode, dc_kbd_keycode, sizeof(kbd->keycode)); @@ -204,27 +202,30 @@ static int probe_maple_kbd(struct device *dev) MAPLE_FUNC_KEYBOARD); mdev->driver = mdrv; + + maple_set_drvdata(mdev, kbd); + return error; fail: input_free_device(idev); kfree(kbd); - mdev->private_data = NULL; + maple_set_drvdata(mdev, NULL); return error; } static int remove_maple_kbd(struct device *dev) { struct maple_device *mdev = to_maple_dev(dev); - struct dc_kbd *kbd; + struct dc_kbd *kbd = maple_get_drvdata(mdev); mutex_lock(&maple_keyb_mutex); - kbd = mdev->private_data; - mdev->private_data = NULL; input_unregister_device(kbd->dev); kfree(kbd); + maple_set_drvdata(mdev, NULL); + mutex_unlock(&maple_keyb_mutex); return 0; } diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c index a6b4dc3cfcb..be77a39f224 100644 --- a/drivers/sh/maple/maple.c +++ b/drivers/sh/maple/maple.c @@ -94,6 +94,7 @@ void maple_driver_unregister(struct maple_driver *drv) { driver_unregister(&drv->drv); } +EXPORT_SYMBOL_GPL(maple_driver_unregister); /* set hardware registers to enable next round of dma */ static void maplebus_dma_reset(void) -- cgit v1.2.3 From b8b572e1015f81b4e748417be2629dfe51ab99f9 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 1 Aug 2008 15:20:30 +1000 Subject: powerpc: Move include files to arch/powerpc/include/asm from include/asm-powerpc. This is the result of a mkdir arch/powerpc/include/asm git mv include/asm-powerpc/* arch/powerpc/include/asm Followed by a few documentation/comment fixups and a couple of places where was being used explicitly. Of the latter only one was outside the arch code and it is a driver only built for powerpc. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- drivers/char/hvc_console.h | 2 +- drivers/char/hvcs.c | 2 +- drivers/infiniband/hw/ehca/ehca_reqs.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h index d9ce1091562..9790201718a 100644 --- a/drivers/char/hvc_console.h +++ b/drivers/char/hvc_console.h @@ -6,7 +6,7 @@ * Ryan S. Arnold * * hvc_console header information: - * moved here from include/asm-powerpc/hvconsole.h + * moved here from arch/powerpc/include/asm/hvconsole.h * and drivers/char/hvc_console.c * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 786d518e947..473d9b14439 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -114,7 +114,7 @@ * the hvcs_final_close() function in order to get it out of the spinlock. * Rearranged hvcs_close(). Cleaned up some printks and did some housekeeping * on the changelog. Removed local CLC_LENGTH and used HVCS_CLC_LENGTH from - * include/asm-powerpc/hvcserver.h + * arch/powerepc/include/asm/hvcserver.h * * 1.3.2 -> 1.3.3 Replaced yield() in hvcs_close() with tty_wait_until_sent() to * prevent possible lockup with realtime scheduling as similarily pointed out by diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c index dd9bc68f1c7..898c8b5c38d 100644 --- a/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/drivers/infiniband/hw/ehca/ehca_reqs.c @@ -42,7 +42,7 @@ */ -#include +#include #include "ehca_classes.h" #include "ehca_tools.h" #include "ehca_qes.h" -- cgit v1.2.3 From 6a9545bd95e88d61df942b9087cb59b8c7a6dc56 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 4 Aug 2008 12:51:06 +0900 Subject: sh: Fix up broken kerneldoc comments. These were completely unparseable, so fix them up. Signed-off-by: Paul Mundt --- drivers/sh/maple/maple.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c index be77a39f224..d1812d32f47 100644 --- a/drivers/sh/maple/maple.c +++ b/drivers/sh/maple/maple.c @@ -147,13 +147,13 @@ static void maple_release_device(struct device *dev) kfree(mdev); } -/* +/** * maple_add_packet - add a single instruction to the queue - * @mdev - maple device - * @function - function on device being queried - * @command - maple command to add - * @length - length of command string (in 32 bit words) - * @data - remainder of command string + * @mdev: maple device + * @function: function on device being queried + * @command: maple command to add + * @length: length of command string (in 32 bit words) + * @data: remainder of command string */ int maple_add_packet(struct maple_device *mdev, u32 function, u32 command, size_t length, void *data) @@ -194,14 +194,15 @@ out: } EXPORT_SYMBOL_GPL(maple_add_packet); -/* +/** * maple_add_packet_sleeps - add a single instruction to the queue - * - waits for lock to be free - * @mdev - maple device - * @function - function on device being queried - * @command - maple command to add - * @length - length of command string (in 32 bit words) - * @data - remainder of command string + * @mdev: maple device + * @function: function on device being queried + * @command: maple command to add + * @length: length of command string (in 32 bit words) + * @data: remainder of command string + * + * Same as maple_add_packet(), but waits for the lock to become free. */ int maple_add_packet_sleeps(struct maple_device *mdev, u32 function, u32 command, size_t length, void *data) -- cgit v1.2.3 From ca579617d81baf5865498eb5fae58e453ee77c2c Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Fri, 18 Jul 2008 13:52:57 +0800 Subject: iwlwifi: add power save to 5000 HW This patch adds support for power save for 5000 HW. Signed-off-by: Mohamed Abbas Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 13 ------------- drivers/net/wireless/iwlwifi/iwl-5000.c | 1 + drivers/net/wireless/iwlwifi/iwl-commands.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-core.h | 1 - drivers/net/wireless/iwlwifi/iwl-dev.h | 3 ++- drivers/net/wireless/iwlwifi/iwl-power.c | 18 ++++++++++++------ drivers/net/wireless/iwlwifi/iwl-power.h | 2 +- 7 files changed, 18 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index ba2df1ba32d..ea23c762957 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -875,18 +875,6 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) return 0; } -/* set card power command */ -static int iwl4965_set_power(struct iwl_priv *priv, - void *cmd) -{ - int ret = 0; - - ret = iwl_send_cmd_pdu_async(priv, POWER_TABLE_CMD, - sizeof(struct iwl4965_powertable_cmd), - cmd, NULL); - return ret; -} - static s32 iwl4965_math_div_round(s32 num, s32 denom, s32 *res) { s32 sign = 1; @@ -2440,7 +2428,6 @@ static struct iwl_lib_ops iwl4965_lib = { .check_version = iwl4965_eeprom_check_version, .query_addr = iwlcore_eeprom_query_addr, }, - .set_power = iwl4965_set_power, .send_tx_power = iwl4965_send_tx_power, .update_chain_flags = iwl4965_update_chain_flags, .temperature = iwl4965_temperature_calib, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 878d6193b23..f91c54b5ff5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1474,6 +1474,7 @@ static struct iwl_lib_ops iwl5000_lib = { .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, .temperature = iwl5000_temperature, + .update_chain_flags = iwl4965_update_chain_flags, .apm_ops = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index e9bb1de0ce3..6f3555ffe52 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1993,7 +1993,7 @@ struct iwl4965_spectrum_notification { *****************************************************************************/ /** - * struct iwl4965_powertable_cmd - Power Table Command + * struct iwl_powertable_cmd - Power Table Command * @flags: See below: * * POWER_TABLE_CMD = 0x77 (command, has simple generic response) @@ -2027,7 +2027,7 @@ struct iwl4965_spectrum_notification { #define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le16(1 << 3) #define IWL_POWER_FAST_PD __constant_cpu_to_le16(1 << 4) -struct iwl4965_powertable_cmd { +struct iwl_powertable_cmd { __le16 flags; u8 keep_alive_seconds; u8 debug_flags; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index db66114f1e5..eaefa42f37c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -139,7 +139,6 @@ struct iwl_lib_ops { int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); } apm_ops; /* power */ - int (*set_power)(struct iwl_priv *priv, void *cmd); int (*send_tx_power) (struct iwl_priv *priv); void (*update_chain_flags)(struct iwl_priv *priv); void (*temperature) (struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 4d789e353e3..010ed69e0e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -283,7 +283,7 @@ struct iwl_cmd { u32 val32; struct iwl4965_bt_cmd bt; struct iwl4965_rxon_time_cmd rxon_time; - struct iwl4965_powertable_cmd powertable; + struct iwl_powertable_cmd powertable; struct iwl_qosparam_cmd qosparam; struct iwl_tx_cmd tx; struct iwl4965_tx_beacon_cmd tx_beacon; @@ -590,6 +590,7 @@ extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, const u8 *dest, int left); extern void iwl4965_update_chain_flags(struct iwl_priv *priv); int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); +extern int iwl4965_set_power(struct iwl_priv *priv, void *cmd); extern const u8 iwl_bcast_addr[ETH_ALEN]; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 2e71803e09b..e3c71beb01e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -112,6 +112,13 @@ static struct iwl_power_vec_entry range_2[IWL_POWER_AC] = { {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} }; +/* set card power command */ +static int iwl_set_power(struct iwl_priv *priv, void *cmd) +{ + return iwl_send_cmd_pdu_async(priv, POWER_TABLE_CMD, + sizeof(struct iwl_powertable_cmd), + cmd, NULL); +} /* decide the right power level according to association status * and battery status */ @@ -162,7 +169,7 @@ static int iwl_power_init_handle(struct iwl_priv *priv) if (ret != 0) return 0; else { - struct iwl4965_powertable_cmd *cmd; + struct iwl_powertable_cmd *cmd; IWL_DEBUG_POWER("adjust power command flags\n"); @@ -180,7 +187,7 @@ static int iwl_power_init_handle(struct iwl_priv *priv) /* adjust power command according to dtim period and power level*/ static int iwl_update_power_command(struct iwl_priv *priv, - struct iwl4965_powertable_cmd *cmd, + struct iwl_powertable_cmd *cmd, u16 mode) { int ret = 0, i; @@ -204,7 +211,7 @@ static int iwl_update_power_command(struct iwl_priv *priv, range = &pow_data->pwr_range_2[0]; period = pow_data->dtim_period; - memcpy(cmd, &range[mode].cmd, sizeof(struct iwl4965_powertable_cmd)); + memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd)); if (period == 0) { period = 1; @@ -280,7 +287,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh) if (!iwl_is_rfkill(priv) && !setting->power_disabled && ((setting->power_mode != final_mode) || refresh)) { - struct iwl4965_powertable_cmd cmd; + struct iwl_powertable_cmd cmd; if (final_mode != IWL_POWER_MODE_CAM) set_bit(STATUS_POWER_PMI, &priv->status); @@ -291,8 +298,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh) if (final_mode == IWL_POWER_INDEX_5) cmd.flags |= IWL_POWER_FAST_PD; - if (priv->cfg->ops->lib->set_power) - ret = priv->cfg->ops->lib->set_power(priv, &cmd); + ret = iwl_set_power(priv, &cmd); if (final_mode == IWL_POWER_MODE_CAM) clear_bit(STATUS_POWER_PMI, &priv->status); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index b066724a1c2..801f6143a42 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -46,7 +46,7 @@ struct iwl_priv; /* Power management (not Tx power) structures */ struct iwl_power_vec_entry { - struct iwl4965_powertable_cmd cmd; + struct iwl_powertable_cmd cmd; u8 no_dtim; }; -- cgit v1.2.3 From 298df1f62aa69881528bf0f1c3c14395bc447846 Mon Sep 17 00:00:00 2001 From: Esti Kummer Date: Fri, 18 Jul 2008 13:52:58 +0800 Subject: iwlwifi: corrects power_level in sysfs This patch corrects power_level in sysfs. Signed-off-by: Esti Kummer Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-power.c | 27 ++++++++----- drivers/net/wireless/iwlwifi/iwl-power.h | 31 +++++++++----- drivers/net/wireless/iwlwifi/iwl4965-base.c | 63 +++++++++-------------------- 3 files changed, 58 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index e3c71beb01e..028e3053c0c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -82,7 +82,7 @@ /* default power management (not Tx power) table values */ /* for tim 0-10 */ -static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = { +static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, @@ -93,7 +93,7 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = { /* for tim = 3-10 */ -static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = { +static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, @@ -103,7 +103,7 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = { }; /* for tim > 11 */ -static struct iwl_power_vec_entry range_2[IWL_POWER_AC] = { +static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, @@ -124,7 +124,7 @@ static int iwl_set_power(struct iwl_priv *priv, void *cmd) */ static u16 iwl_get_auto_power_mode(struct iwl_priv *priv) { - u16 mode = priv->power_data.user_power_setting; + u16 mode; switch (priv->power_data.user_power_setting) { case IWL_POWER_AUTO: @@ -136,12 +136,16 @@ static u16 iwl_get_auto_power_mode(struct iwl_priv *priv) else mode = IWL_POWER_ON_AC_DISASSOC; break; + /* FIXME: remove battery and ac from here */ case IWL_POWER_BATTERY: mode = IWL_POWER_INDEX_3; break; case IWL_POWER_AC: mode = IWL_POWER_MODE_CAM; break; + default: + mode = priv->power_data.user_power_setting; + break; } return mode; } @@ -151,7 +155,7 @@ static int iwl_power_init_handle(struct iwl_priv *priv) { int ret = 0, i; struct iwl_power_mgr *pow_data; - int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC; + int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_MAX; u16 pci_pm; IWL_DEBUG_POWER("Initialize power \n"); @@ -173,7 +177,7 @@ static int iwl_power_init_handle(struct iwl_priv *priv) IWL_DEBUG_POWER("adjust power command flags\n"); - for (i = 0; i < IWL_POWER_AC; i++) { + for (i = 0; i < IWL_POWER_MAX; i++) { cmd = &pow_data->pwr_range_0[i].cmd; if (pci_pm & 0x1) @@ -265,17 +269,18 @@ int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh) * else user level */ switch (setting->system_power_setting) { - case IWL_POWER_AUTO: + case IWL_POWER_SYS_AUTO: final_mode = iwl_get_auto_power_mode(priv); break; - case IWL_POWER_BATTERY: + case IWL_POWER_SYS_BATTERY: final_mode = IWL_POWER_INDEX_3; break; - case IWL_POWER_AC: + case IWL_POWER_SYS_AC: final_mode = IWL_POWER_MODE_CAM; break; default: - final_mode = setting->system_power_setting; + final_mode = IWL_POWER_INDEX_3; + WARN_ON(1); } if (setting->critical_power_setting > final_mode) @@ -394,7 +399,7 @@ void iwl_power_initialize(struct iwl_priv *priv) iwl_power_init_handle(priv); priv->power_data.user_power_setting = IWL_POWER_AUTO; priv->power_data.power_disabled = 0; - priv->power_data.system_power_setting = IWL_POWER_AUTO; + priv->power_data.system_power_setting = IWL_POWER_SYS_AUTO; priv->power_data.is_battery_active = 0; priv->power_data.power_disabled = 0; priv->power_data.critical_power_setting = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 801f6143a42..abcbbf96a84 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -33,12 +33,25 @@ struct iwl_priv; -#define IWL_POWER_MODE_CAM 0x00 /* Continuously Aware Mode, always on */ -#define IWL_POWER_INDEX_3 0x03 -#define IWL_POWER_INDEX_5 0x05 -#define IWL_POWER_AC 0x06 -#define IWL_POWER_BATTERY 0x07 -#define IWL_POWER_AUTO 0x08 +enum { + IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */ + IWL_POWER_INDEX_1, + IWL_POWER_INDEX_2, + IWL_POWER_INDEX_3, + IWL_POWER_INDEX_4, + IWL_POWER_INDEX_5, + IWL_POWER_AUTO, + IWL_POWER_MAX = IWL_POWER_AUTO, + IWL_POWER_AC, + IWL_POWER_BATTERY, +}; + +enum { + IWL_POWER_SYS_AUTO, + IWL_POWER_SYS_AC, + IWL_POWER_SYS_BATTERY, +}; + #define IWL_POWER_LIMIT 0x08 #define IWL_POWER_MASK 0x0F #define IWL_POWER_ENABLED 0x10 @@ -52,9 +65,9 @@ struct iwl_power_vec_entry { struct iwl_power_mgr { spinlock_t lock; - struct iwl_power_vec_entry pwr_range_0[IWL_POWER_AC]; - struct iwl_power_vec_entry pwr_range_1[IWL_POWER_AC]; - struct iwl_power_vec_entry pwr_range_2[IWL_POWER_AC]; + struct iwl_power_vec_entry pwr_range_0[IWL_POWER_MAX]; + struct iwl_power_vec_entry pwr_range_1[IWL_POWER_MAX]; + struct iwl_power_vec_entry pwr_range_2[IWL_POWER_MAX]; u32 dtim_period; /* final power level that used to calculate final power command */ u8 power_mode; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 71f5da3fe5c..2001b09738f 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -3800,76 +3800,53 @@ static ssize_t store_power_level(struct device *d, const char *buf, size_t count) { struct iwl_priv *priv = dev_get_drvdata(d); - int rc; + int ret; int mode; mode = simple_strtoul(buf, NULL, 0); mutex_lock(&priv->mutex); if (!iwl_is_ready(priv)) { - rc = -EAGAIN; + ret = -EAGAIN; goto out; } - rc = iwl_power_set_user_mode(priv, mode); - if (rc) { + ret = iwl_power_set_user_mode(priv, mode); + if (ret) { IWL_DEBUG_MAC80211("failed setting power mode.\n"); goto out; } - rc = count; + ret = count; out: mutex_unlock(&priv->mutex); - return rc; + return ret; } -#define MAX_WX_STRING 80 - -/* Values are in microsecond */ -static const s32 timeout_duration[] = { - 350000, - 250000, - 75000, - 37000, - 25000, -}; -static const s32 period_duration[] = { - 400000, - 700000, - 1000000, - 1000000, - 1000000 -}; - static ssize_t show_power_level(struct device *d, struct device_attribute *attr, char *buf) { struct iwl_priv *priv = dev_get_drvdata(d); + int mode = priv->power_data.user_power_setting; + int system = priv->power_data.system_power_setting; int level = priv->power_data.power_mode; char *p = buf; - p += sprintf(p, "%d ", level); - switch (level) { - case IWL_POWER_MODE_CAM: - case IWL_POWER_AC: - p += sprintf(p, "(AC)"); + switch (system) { + case IWL_POWER_SYS_AUTO: + p += sprintf(p, "SYSTEM:auto"); break; - case IWL_POWER_BATTERY: - p += sprintf(p, "(BATTERY)"); + case IWL_POWER_SYS_AC: + p += sprintf(p, "SYSTEM:ac"); + break; + case IWL_POWER_SYS_BATTERY: + p += sprintf(p, "SYSTEM:battery"); break; - default: - p += sprintf(p, - "(Timeout %dms, Period %dms)", - timeout_duration[level - 1] / 1000, - period_duration[level - 1] / 1000); } -/* - if (!(priv->power_mode & IWL_POWER_ENABLED)) - p += sprintf(p, " OFF\n"); - else - p += sprintf(p, " \n"); -*/ - p += sprintf(p, " \n"); + + p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO)?"fixed":"auto"); + p += sprintf(p, "\tINDEX:%d", level); + p += sprintf(p, "\n"); return (p - buf + 1); } -- cgit v1.2.3 From d783b061077f92af55244aef1df8780b0f46b5af Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 18 Jul 2008 13:53:02 +0800 Subject: iwlwifi: move iwl4965_mac_ampdu_action to iwl4965-base.c This patch moves iwl4965_mac_ampdu_action to iwl4965-base.c. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 33 --------------------------- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 ---- drivers/net/wireless/iwlwifi/iwl4965-base.c | 35 ++++++++++++++++++++++++++++- 3 files changed, 34 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index ea23c762957..3cc6f00d96c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2067,39 +2067,6 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, return 0; } -int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, - enum ieee80211_ampdu_mlme_action action, - const u8 *addr, u16 tid, u16 *ssn) -{ - struct iwl_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n", - print_mac(mac, addr), tid); - - if (!(priv->cfg->sku & IWL_SKU_N)) - return -EACCES; - - switch (action) { - case IEEE80211_AMPDU_RX_START: - IWL_DEBUG_HT("start Rx\n"); - return iwl_rx_agg_start(priv, addr, tid, *ssn); - case IEEE80211_AMPDU_RX_STOP: - IWL_DEBUG_HT("stop Rx\n"); - return iwl_rx_agg_stop(priv, addr, tid); - case IEEE80211_AMPDU_TX_START: - IWL_DEBUG_HT("start Tx\n"); - return iwl_tx_agg_start(priv, addr, tid, ssn); - case IEEE80211_AMPDU_TX_STOP: - IWL_DEBUG_HT("stop Tx\n"); - return iwl_tx_agg_stop(priv, addr, tid); - default: - IWL_DEBUG_HT("unknown\n"); - return -EINVAL; - break; - } - return 0; -} static u16 iwl4965_get_hcmd_size(u8 cmd_id, u16 len) { diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 010ed69e0e5..d2d4beab82a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -643,10 +643,6 @@ struct iwl_priv; * Forward declare iwl-4965.c functions for iwl-base.c */ extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv); - -int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, - enum ieee80211_ampdu_mlme_action action, - const u8 *addr, u16 tid, u16 *ssn); int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 2001b09738f..a34280f65c1 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -65,7 +65,7 @@ * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk */ -#define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link 4965AGN driver for Linux" +#define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link AGN driver for Linux" #ifdef CONFIG_IWLWIFI_DEBUG #define VD "d" @@ -3345,6 +3345,39 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, return 0; } +static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, + enum ieee80211_ampdu_mlme_action action, + const u8 *addr, u16 tid, u16 *ssn) +{ + struct iwl_priv *priv = hw->priv; + DECLARE_MAC_BUF(mac); + + IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n", + print_mac(mac, addr), tid); + + if (!(priv->cfg->sku & IWL_SKU_N)) + return -EACCES; + + switch (action) { + case IEEE80211_AMPDU_RX_START: + IWL_DEBUG_HT("start Rx\n"); + return iwl_rx_agg_start(priv, addr, tid, *ssn); + case IEEE80211_AMPDU_RX_STOP: + IWL_DEBUG_HT("stop Rx\n"); + return iwl_rx_agg_stop(priv, addr, tid); + case IEEE80211_AMPDU_TX_START: + IWL_DEBUG_HT("start Tx\n"); + return iwl_tx_agg_start(priv, addr, tid, ssn); + case IEEE80211_AMPDU_TX_STOP: + IWL_DEBUG_HT("stop Tx\n"); + return iwl_tx_agg_stop(priv, addr, tid); + default: + IWL_DEBUG_HT("unknown\n"); + return -EINVAL; + break; + } + return 0; +} static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats) { -- cgit v1.2.3 From 4bf64efd26f5610cde4fb7846e2f37bd1f62d3a9 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 18 Jul 2008 13:53:03 +0800 Subject: iwlwifi: move beacon handling to iwl4965-base.c This patch concentrates becaon handling in iwl4965-base.c. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 32 ----------------------- drivers/net/wireless/iwlwifi/iwl-commands.h | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 +-- drivers/net/wireless/iwlwifi/iwl4965-base.c | 39 ++++++++++++++++++++++++++--- 4 files changed, 37 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 3cc6f00d96c..9ae8525b9b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1689,38 +1689,6 @@ static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv) return le32_to_cpu(s->rb_closed) & 0xFFF; } -unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl_frame *frame, u8 rate) -{ - struct iwl4965_tx_beacon_cmd *tx_beacon_cmd; - unsigned int frame_size; - - tx_beacon_cmd = &frame->u.beacon; - memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); - - tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id; - tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - - frame_size = iwl4965_fill_beacon_frame(priv, - tx_beacon_cmd->frame, - iwl_bcast_addr, - sizeof(frame->u) - sizeof(*tx_beacon_cmd)); - - BUG_ON(frame_size > MAX_MPDU_SIZE); - tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); - - if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP)) - tx_beacon_cmd->tx.rate_n_flags = - iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK); - else - tx_beacon_cmd->tx.rate_n_flags = - iwl_hw_set_rate_n_flags(rate, 0); - - tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK | - TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK); - return (sizeof(*tx_beacon_cmd) + frame_size); -} - static int iwl4965_alloc_shared_mem(struct iwl_priv *priv) { priv->shared_virt = pci_alloc_consistent(priv->pci_dev, diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 6f3555ffe52..cd6d668f4e0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2324,7 +2324,7 @@ struct iwl4965_beacon_notif { /* * REPLY_TX_BEACON = 0x91 (command, has simple generic response) */ -struct iwl4965_tx_beacon_cmd { +struct iwl_tx_beacon_cmd { struct iwl_tx_cmd tx; __le16 tim_idx; u8 tim_size; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index d2d4beab82a..ff16cca2b8c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -219,7 +219,7 @@ enum iwl_pwr_src { struct iwl_frame { union { struct ieee80211_hdr frame; - struct iwl4965_tx_beacon_cmd beacon; + struct iwl_tx_beacon_cmd beacon; u8 raw[IEEE80211_FRAME_LEN]; u8 cmd[360]; } u; @@ -286,7 +286,6 @@ struct iwl_cmd { struct iwl_powertable_cmd powertable; struct iwl_qosparam_cmd qosparam; struct iwl_tx_cmd tx; - struct iwl4965_tx_beacon_cmd tx_beacon; struct iwl4965_rxon_assoc_cmd rxon_assoc; struct iwl_rem_sta_cmd rm_sta; u8 *indirect; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index a34280f65c1..94ce026ba60 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -444,11 +444,10 @@ static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) list_add(&frame->list, &priv->free_frames); } -unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, - const u8 *dest, int left) +static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, + struct ieee80211_hdr *hdr, + const u8 *dest, int left) { - if (!iwl_is_associated(priv) || !priv->ibss_beacon || ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) && (priv->iw_mode != IEEE80211_IF_TYPE_AP))) @@ -487,6 +486,38 @@ static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) return IWL_RATE_6M_PLCP; } +unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, + struct iwl_frame *frame, u8 rate) +{ + struct iwl_tx_beacon_cmd *tx_beacon_cmd; + unsigned int frame_size; + + tx_beacon_cmd = &frame->u.beacon; + memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); + + tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id; + tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + + frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame, + iwl_bcast_addr, + sizeof(frame->u) - sizeof(*tx_beacon_cmd)); + + BUG_ON(frame_size > MAX_MPDU_SIZE); + tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); + + if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP)) + tx_beacon_cmd->tx.rate_n_flags = + iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK); + else + tx_beacon_cmd->tx.rate_n_flags = + iwl_hw_set_rate_n_flags(rate, 0); + + tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK | + TX_CMD_FLG_TSF_MSK | + TX_CMD_FLG_STA_RATE_MSK; + + return sizeof(*tx_beacon_cmd) + frame_size; +} static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) { struct iwl_frame *frame; -- cgit v1.2.3 From e2e3c57b271d74ed8fd4d378f1517525ef7e5921 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 18 Jul 2008 13:53:04 +0800 Subject: iwlwifi: move iwl4965_set_pwr_src to iwl4965-base.c This patch moves iwl4965_set_pwr_src to iwl4965-base.c. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 33 ----------------------------- drivers/net/wireless/iwlwifi/iwl4965-base.c | 31 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 9ae8525b9b6..c0ba28fa672 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -341,39 +341,6 @@ err: return -EINVAL; } -int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) -{ - int ret; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) { - spin_unlock_irqrestore(&priv->lock, flags); - return ret; - } - - if (src == IWL_PWR_SRC_VAUX) { - u32 val; - ret = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE, - &val); - - if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) { - iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_PWR_SRC_VAUX, - ~APMG_PS_CTRL_MSK_PWR_SRC); - } - } else { - iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, - ~APMG_PS_CTRL_MSK_PWR_SRC); - } - - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - return ret; -} /* * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 94ce026ba60..ac02342d228 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -1262,6 +1262,37 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, wake_up_interruptible(&priv->wait_command_queue); } +int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + ret = iwl_grab_nic_access(priv); + if (ret) + goto err; + + if (src == IWL_PWR_SRC_VAUX) { + u32 val; + ret = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE, + &val); + + if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) + iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VAUX, + ~APMG_PS_CTRL_MSK_PWR_SRC); + } else { + iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, + ~APMG_PS_CTRL_MSK_PWR_SRC); + } + + iwl_release_nic_access(priv); +err: + spin_unlock_irqrestore(&priv->lock, flags); + return ret; +} + /** * iwl4965_setup_rx_handlers - Initialize Rx handler callbacks * -- cgit v1.2.3 From e227ceac8429ecd775c213838f0415700727b7b4 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 18 Jul 2008 13:53:05 +0800 Subject: iwlwifi: rename iwl-4695-rs to iwl-agn-rs This patch renames iwl-4965-rs to iwl-agn-rs as it provides rate scale capability for all AGN capable iwlwifi drivers. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Makefile | 2 +- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 2713 --------------------------- drivers/net/wireless/iwlwifi/iwl-4965-rs.h | 318 ---- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 2704 ++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-agn-rs.h | 318 ++++ drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 2 +- drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 6 +- 9 files changed, 3029 insertions(+), 3038 deletions(-) delete mode 100644 drivers/net/wireless/iwlwifi/iwl-4965-rs.c delete mode 100644 drivers/net/wireless/iwlwifi/iwl-4965-rs.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-agn-rs.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-agn-rs.h (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 1f52b92f08b..f50d2f8fd5c 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -11,7 +11,7 @@ iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl3945-$(CONFIG_IWL3945_LEDS) += iwl-3945-led.o obj-$(CONFIG_IWL4965) += iwl4965.o -iwl4965-objs := iwl4965-base.o iwl-4965.o iwl-4965-rs.o +iwl4965-objs := iwl4965-base.o iwl-4965.o iwl-agn-rs.o ifeq ($(CONFIG_IWL5000),y) iwl4965-objs += iwl-5000.o diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c deleted file mode 100644 index 3ccb84aa5db..00000000000 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ /dev/null @@ -1,2713 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * James P. Ketrenos - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "../net/mac80211/rate.h" - -#include "iwl-dev.h" -#include "iwl-sta.h" -#include "iwl-core.h" -#include "iwl-helpers.h" - -#define RS_NAME "iwl-4965-rs" - -#define NUM_TRY_BEFORE_ANT_TOGGLE 1 -#define IWL_NUMBER_TRY 1 -#define IWL_HT_NUMBER_TRY 3 - -#define IWL_RATE_MAX_WINDOW 62 /* # tx in history window */ -#define IWL_RATE_MIN_FAILURE_TH 6 /* min failures to calc tpt */ -#define IWL_RATE_MIN_SUCCESS_TH 8 /* min successes to calc tpt */ - -/* max time to accum history 2 seconds */ -#define IWL_RATE_SCALE_FLUSH_INTVL (2*HZ) - -static u8 rs_ht_to_legacy[] = { - IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, - IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, - IWL_RATE_6M_INDEX, - IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX, - IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX, - IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX, - IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX -}; - -static const u8 ant_toggle_lookup[] = { - /*ANT_NONE -> */ ANT_NONE, - /*ANT_A -> */ ANT_B, - /*ANT_B -> */ ANT_C, - /*ANT_AB -> */ ANT_BC, - /*ANT_C -> */ ANT_A, - /*ANT_AC -> */ ANT_AB, - /*ANT_BC -> */ ANT_AC, - /*ANT_ABC -> */ ANT_ABC, -}; - -/** - * struct iwl4965_rate_scale_data -- tx success history for one rate - */ -struct iwl4965_rate_scale_data { - u64 data; /* bitmap of successful frames */ - s32 success_counter; /* number of frames successful */ - s32 success_ratio; /* per-cent * 128 */ - s32 counter; /* number of frames attempted */ - s32 average_tpt; /* success ratio * expected throughput */ - unsigned long stamp; -}; - -/** - * struct iwl4965_scale_tbl_info -- tx params and success history for all rates - * - * There are two of these in struct iwl4965_lq_sta, - * one for "active", and one for "search". - */ -struct iwl4965_scale_tbl_info { - enum iwl_table_type lq_type; - u8 ant_type; - u8 is_SGI; /* 1 = short guard interval */ - u8 is_fat; /* 1 = 40 MHz channel width */ - u8 is_dup; /* 1 = duplicated data streams */ - u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ - s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ - u32 current_rate; /* rate_n_flags, uCode API format */ - struct iwl4965_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ -}; - -struct iwl4965_traffic_load { - unsigned long time_stamp; /* age of the oldest statistics */ - u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time - * slice */ - u32 total; /* total num of packets during the - * last TID_MAX_TIME_DIFF */ - u8 queue_count; /* number of queues that has - * been used since the last cleanup */ - u8 head; /* start of the circular buffer */ -}; - -/** - * struct iwl4965_lq_sta -- driver's rate scaling private structure - * - * Pointer to this gets passed back and forth between driver and mac80211. - */ -struct iwl4965_lq_sta { - u8 active_tbl; /* index of active table, range 0-1 */ - u8 enable_counter; /* indicates HT mode */ - u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */ - u8 search_better_tbl; /* 1: currently trying alternate mode */ - s32 last_tpt; - - /* The following determine when to search for a new mode */ - u32 table_count_limit; - u32 max_failure_limit; /* # failed frames before new search */ - u32 max_success_limit; /* # successful frames before new search */ - u32 table_count; - u32 total_failed; /* total failed frames, any/all rates */ - u32 total_success; /* total successful frames, any/all rates */ - u32 flush_timer; /* time staying in mode before new search */ - - u8 action_counter; /* # mode-switch actions tried */ - u8 is_green; - u8 is_dup; - enum ieee80211_band band; - u8 ibss_sta_added; - - /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ - u32 supp_rates; - u16 active_legacy_rate; - u16 active_siso_rate; - u16 active_mimo2_rate; - u16 active_mimo3_rate; - u16 active_rate_basic; - - struct iwl_link_quality_cmd lq; - struct iwl4965_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ - struct iwl4965_traffic_load load[TID_MAX_LOAD_COUNT]; - u8 tx_agg_tid_en; -#ifdef CONFIG_MAC80211_DEBUGFS - struct dentry *rs_sta_dbgfs_scale_table_file; - struct dentry *rs_sta_dbgfs_stats_table_file; - struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; - u32 dbg_fixed_rate; -#endif - struct iwl_priv *drv; -}; - -static void rs_rate_scale_perform(struct iwl_priv *priv, - struct net_device *dev, - struct ieee80211_hdr *hdr, - struct sta_info *sta); -static void rs_fill_link_cmd(const struct iwl_priv *priv, - struct iwl4965_lq_sta *lq_sta, - u32 rate_n_flags); - - -#ifdef CONFIG_MAC80211_DEBUGFS -static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta, - u32 *rate_n_flags, int index); -#else -static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta, - u32 *rate_n_flags, int index) -{} -#endif - -/* - * Expected throughput metrics for following rates: - * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits - * "G" is the only table that supports CCK (the first 4 rates). - */ -/*FIXME:RS:need to spearate tables for MIMO2/MIMO3*/ -static s32 expected_tpt_A[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186 -}; - -static s32 expected_tpt_G[IWL_RATE_COUNT] = { - 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 186 -}; - -static s32 expected_tpt_siso20MHz[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 42, 42, 76, 102, 124, 159, 183, 193, 202 -}; - -static s32 expected_tpt_siso20MHzSGI[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 46, 46, 82, 110, 132, 168, 192, 202, 211 -}; - -static s32 expected_tpt_mimo20MHz[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251 -}; - -static s32 expected_tpt_mimo20MHzSGI[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 81, 81, 131, 164, 188, 222, 243, 251, 257 -}; - -static s32 expected_tpt_siso40MHz[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 77, 77, 127, 160, 184, 220, 242, 250, 257 -}; - -static s32 expected_tpt_siso40MHzSGI[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 83, 83, 135, 169, 193, 229, 250, 257, 264 -}; - -static s32 expected_tpt_mimo40MHz[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289 -}; - -static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293 -}; - -static inline u8 rs_extract_rate(u32 rate_n_flags) -{ - return (u8)(rate_n_flags & 0xFF); -} - -static void rs_rate_scale_clear_window(struct iwl4965_rate_scale_data *window) -{ - window->data = 0; - window->success_counter = 0; - window->success_ratio = IWL_INVALID_VALUE; - window->counter = 0; - window->average_tpt = IWL_INVALID_VALUE; - window->stamp = 0; -} - -static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type) -{ - return ((ant_type & valid_antenna) == ant_type); -} - -/* - * removes the old data from the statistics. All data that is older than - * TID_MAX_TIME_DIFF, will be deleted. - */ -static void rs_tl_rm_old_stats(struct iwl4965_traffic_load *tl, u32 curr_time) -{ - /* The oldest age we want to keep */ - u32 oldest_time = curr_time - TID_MAX_TIME_DIFF; - - while (tl->queue_count && - (tl->time_stamp < oldest_time)) { - tl->total -= tl->packet_count[tl->head]; - tl->packet_count[tl->head] = 0; - tl->time_stamp += TID_QUEUE_CELL_SPACING; - tl->queue_count--; - tl->head++; - if (tl->head >= TID_QUEUE_MAX_SIZE) - tl->head = 0; - } -} - -/* - * increment traffic load value for tid and also remove - * any old values if passed the certain time period - */ -static u8 rs_tl_add_packet(struct iwl4965_lq_sta *lq_data, - struct ieee80211_hdr *hdr) -{ - u32 curr_time = jiffies_to_msecs(jiffies); - u32 time_diff; - s32 index; - struct iwl4965_traffic_load *tl = NULL; - __le16 fc = hdr->frame_control; - u8 tid; - - if (ieee80211_is_data_qos(fc)) { - u8 *qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - } else - return MAX_TID_COUNT; - - tl = &lq_data->load[tid]; - - curr_time -= curr_time % TID_ROUND_VALUE; - - /* Happens only for the first packet. Initialize the data */ - if (!(tl->queue_count)) { - tl->total = 1; - tl->time_stamp = curr_time; - tl->queue_count = 1; - tl->head = 0; - tl->packet_count[0] = 1; - return MAX_TID_COUNT; - } - - time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time); - index = time_diff / TID_QUEUE_CELL_SPACING; - - /* The history is too long: remove data that is older than */ - /* TID_MAX_TIME_DIFF */ - if (index >= TID_QUEUE_MAX_SIZE) - rs_tl_rm_old_stats(tl, curr_time); - - index = (tl->head + index) % TID_QUEUE_MAX_SIZE; - tl->packet_count[index] = tl->packet_count[index] + 1; - tl->total = tl->total + 1; - - if ((index + 1) > tl->queue_count) - tl->queue_count = index + 1; - - return tid; -} - -/* - get the traffic load value for tid -*/ -static u32 rs_tl_get_load(struct iwl4965_lq_sta *lq_data, u8 tid) -{ - u32 curr_time = jiffies_to_msecs(jiffies); - u32 time_diff; - s32 index; - struct iwl4965_traffic_load *tl = NULL; - - if (tid >= TID_MAX_LOAD_COUNT) - return 0; - - tl = &(lq_data->load[tid]); - - curr_time -= curr_time % TID_ROUND_VALUE; - - if (!(tl->queue_count)) - return 0; - - time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time); - index = time_diff / TID_QUEUE_CELL_SPACING; - - /* The history is too long: remove data that is older than */ - /* TID_MAX_TIME_DIFF */ - if (index >= TID_QUEUE_MAX_SIZE) - rs_tl_rm_old_stats(tl, curr_time); - - return tl->total; -} - -static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, - struct iwl4965_lq_sta *lq_data, u8 tid, - struct sta_info *sta) -{ - unsigned long state; - DECLARE_MAC_BUF(mac); - - spin_lock_bh(&sta->lock); - state = sta->ampdu_mlme.tid_state_tx[tid]; - spin_unlock_bh(&sta->lock); - - if (state == HT_AGG_STATE_IDLE && - rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { - IWL_DEBUG_HT("Starting Tx agg: STA: %s tid: %d\n", - print_mac(mac, sta->addr), tid); - ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid); - } -} - -static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid, - struct iwl4965_lq_sta *lq_data, - struct sta_info *sta) -{ - if ((tid < TID_MAX_LOAD_COUNT)) - rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta); - else if (tid == IWL_AGG_ALL_TID) - for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) - rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta); -} - -static inline int get_num_of_ant_from_rate(u32 rate_n_flags) -{ - return (!!(rate_n_flags & RATE_MCS_ANT_A_MSK) + - !!(rate_n_flags & RATE_MCS_ANT_B_MSK) + - !!(rate_n_flags & RATE_MCS_ANT_C_MSK)); -} - -/** - * rs_collect_tx_data - Update the success/failure sliding window - * - * We keep a sliding window of the last 62 packets transmitted - * at this rate. window->data contains the bitmask of successful - * packets. - */ -static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows, - int scale_index, s32 tpt, int retries, - int successes) -{ - struct iwl4965_rate_scale_data *window = NULL; - static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1)); - s32 fail_count; - - if (scale_index < 0 || scale_index >= IWL_RATE_COUNT) - return -EINVAL; - - /* Select data for current tx bit rate */ - window = &(windows[scale_index]); - - /* - * Keep track of only the latest 62 tx frame attempts in this rate's - * history window; anything older isn't really relevant any more. - * If we have filled up the sliding window, drop the oldest attempt; - * if the oldest attempt (highest bit in bitmap) shows "success", - * subtract "1" from the success counter (this is the main reason - * we keep these bitmaps!). - */ - while (retries > 0) { - if (window->counter >= IWL_RATE_MAX_WINDOW) { - - /* remove earliest */ - window->counter = IWL_RATE_MAX_WINDOW - 1; - - if (window->data & mask) { - window->data &= ~mask; - window->success_counter--; - } - } - - /* Increment frames-attempted counter */ - window->counter++; - - /* Shift bitmap by one frame (throw away oldest history), - * OR in "1", and increment "success" if this - * frame was successful. */ - window->data <<= 1;; - if (successes > 0) { - window->success_counter++; - window->data |= 0x1; - successes--; - } - - retries--; - } - - /* Calculate current success ratio, avoid divide-by-0! */ - if (window->counter > 0) - window->success_ratio = 128 * (100 * window->success_counter) - / window->counter; - else - window->success_ratio = IWL_INVALID_VALUE; - - fail_count = window->counter - window->success_counter; - - /* Calculate average throughput, if we have enough history. */ - if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) || - (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH)) - window->average_tpt = (window->success_ratio * tpt + 64) / 128; - else - window->average_tpt = IWL_INVALID_VALUE; - - /* Tag this window as having been updated */ - window->stamp = jiffies; - - return 0; -} - -/* - * Fill uCode API rate_n_flags field, based on "search" or "active" table. - */ -/* FIXME:RS:remove this function and put the flags statically in the table */ -static u32 rate_n_flags_from_tbl(struct iwl4965_scale_tbl_info *tbl, - int index, u8 use_green) -{ - u32 rate_n_flags = 0; - - if (is_legacy(tbl->lq_type)) { - rate_n_flags = iwl_rates[index].plcp; - if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) - rate_n_flags |= RATE_MCS_CCK_MSK; - - } else if (is_Ht(tbl->lq_type)) { - if (index > IWL_LAST_OFDM_RATE) { - IWL_ERROR("invalid HT rate index %d\n", index); - index = IWL_LAST_OFDM_RATE; - } - rate_n_flags = RATE_MCS_HT_MSK; - - if (is_siso(tbl->lq_type)) - rate_n_flags |= iwl_rates[index].plcp_siso; - else if (is_mimo2(tbl->lq_type)) - rate_n_flags |= iwl_rates[index].plcp_mimo2; - else - rate_n_flags |= iwl_rates[index].plcp_mimo3; - } else { - IWL_ERROR("Invalid tbl->lq_type %d\n", tbl->lq_type); - } - - rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) & - RATE_MCS_ANT_ABC_MSK); - - if (is_Ht(tbl->lq_type)) { - if (tbl->is_fat) { - if (tbl->is_dup) - rate_n_flags |= RATE_MCS_DUP_MSK; - else - rate_n_flags |= RATE_MCS_FAT_MSK; - } - if (tbl->is_SGI) - rate_n_flags |= RATE_MCS_SGI_MSK; - - if (use_green) { - rate_n_flags |= RATE_MCS_GF_MSK; - if (is_siso(tbl->lq_type) && tbl->is_SGI) { - rate_n_flags &= ~RATE_MCS_SGI_MSK; - IWL_ERROR("GF was set with SGI:SISO\n"); - } - } - } - return rate_n_flags; -} - -/* - * Interpret uCode API's rate_n_flags format, - * fill "search" or "active" tx mode table. - */ -static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, - enum ieee80211_band band, - struct iwl4965_scale_tbl_info *tbl, - int *rate_idx) -{ - u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK); - u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags); - u8 mcs; - - *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); - - if (*rate_idx == IWL_RATE_INVALID) { - *rate_idx = -1; - return -EINVAL; - } - tbl->is_SGI = 0; /* default legacy setup */ - tbl->is_fat = 0; - tbl->is_dup = 0; - tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS); - tbl->lq_type = LQ_NONE; - - /* legacy rate format */ - if (!(rate_n_flags & RATE_MCS_HT_MSK)) { - if (num_of_ant == 1) { - if (band == IEEE80211_BAND_5GHZ) - tbl->lq_type = LQ_A; - else - tbl->lq_type = LQ_G; - } - /* HT rate format */ - } else { - if (rate_n_flags & RATE_MCS_SGI_MSK) - tbl->is_SGI = 1; - - if ((rate_n_flags & RATE_MCS_FAT_MSK) || - (rate_n_flags & RATE_MCS_DUP_MSK)) - tbl->is_fat = 1; - - if (rate_n_flags & RATE_MCS_DUP_MSK) - tbl->is_dup = 1; - - mcs = rs_extract_rate(rate_n_flags); - - /* SISO */ - if (mcs <= IWL_RATE_SISO_60M_PLCP) { - if (num_of_ant == 1) - tbl->lq_type = LQ_SISO; /*else NONE*/ - /* MIMO2 */ - } else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) { - if (num_of_ant == 2) - tbl->lq_type = LQ_MIMO2; - /* MIMO3 */ - } else { - if (num_of_ant == 3) - tbl->lq_type = LQ_MIMO3; - } - } - return 0; -} - -/* switch to another antenna/antennas and return 1 */ -/* if no other valid antenna found, return 0 */ -static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, - struct iwl4965_scale_tbl_info *tbl) -{ - u8 new_ant_type; - - if (!tbl->ant_type || tbl->ant_type > ANT_ABC) - return 0; - - if (!rs_is_valid_ant(valid_ant, tbl->ant_type)) - return 0; - - new_ant_type = ant_toggle_lookup[tbl->ant_type]; - - while ((new_ant_type != tbl->ant_type) && - !rs_is_valid_ant(valid_ant, new_ant_type)) - new_ant_type = ant_toggle_lookup[new_ant_type]; - - if (new_ant_type == tbl->ant_type) - return 0; - - tbl->ant_type = new_ant_type; - *rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK; - *rate_n_flags |= new_ant_type << RATE_MCS_ANT_POS; - return 1; -} - -/* FIXME:RS: in 4965 we don't use greenfield at all */ -/* FIXME:RS: don't use greenfield for now in TX */ -#if 0 -static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf) -{ - return ((conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && - priv->current_ht_config.is_green_field && - !priv->current_ht_config.non_GF_STA_present); -} -#endif -static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf) -{ - return 0; -} - -/** - * rs_get_supported_rates - get the available rates - * - * if management frame or broadcast frame only return - * basic available rates. - * - */ -static u16 rs_get_supported_rates(struct iwl4965_lq_sta *lq_sta, - struct ieee80211_hdr *hdr, - enum iwl_table_type rate_type) -{ - if (hdr && is_multicast_ether_addr(hdr->addr1) && - lq_sta->active_rate_basic) - return lq_sta->active_rate_basic; - - if (is_legacy(rate_type)) { - return lq_sta->active_legacy_rate; - } else { - if (is_siso(rate_type)) - return lq_sta->active_siso_rate; - else if (is_mimo2(rate_type)) - return lq_sta->active_mimo2_rate; - else - return lq_sta->active_mimo3_rate; - } -} - -static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask, - int rate_type) -{ - u8 high = IWL_RATE_INVALID; - u8 low = IWL_RATE_INVALID; - - /* 802.11A or ht walks to the next literal adjacent rate in - * the rate table */ - if (is_a_band(rate_type) || !is_legacy(rate_type)) { - int i; - u32 mask; - - /* Find the previous rate that is in the rate mask */ - i = index - 1; - for (mask = (1 << i); i >= 0; i--, mask >>= 1) { - if (rate_mask & mask) { - low = i; - break; - } - } - - /* Find the next rate that is in the rate mask */ - i = index + 1; - for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) { - if (rate_mask & mask) { - high = i; - break; - } - } - - return (high << 8) | low; - } - - low = index; - while (low != IWL_RATE_INVALID) { - low = iwl_rates[low].prev_rs; - if (low == IWL_RATE_INVALID) - break; - if (rate_mask & (1 << low)) - break; - IWL_DEBUG_RATE("Skipping masked lower rate: %d\n", low); - } - - high = index; - while (high != IWL_RATE_INVALID) { - high = iwl_rates[high].next_rs; - if (high == IWL_RATE_INVALID) - break; - if (rate_mask & (1 << high)) - break; - IWL_DEBUG_RATE("Skipping masked higher rate: %d\n", high); - } - - return (high << 8) | low; -} - -static u32 rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta, - struct iwl4965_scale_tbl_info *tbl, u8 scale_index, - u8 ht_possible) -{ - s32 low; - u16 rate_mask; - u16 high_low; - u8 switch_to_legacy = 0; - u8 is_green = lq_sta->is_green; - - /* check if we need to switch from HT to legacy rates. - * assumption is that mandatory rates (1Mbps or 6Mbps) - * are always supported (spec demand) */ - if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) { - switch_to_legacy = 1; - scale_index = rs_ht_to_legacy[scale_index]; - if (lq_sta->band == IEEE80211_BAND_5GHZ) - tbl->lq_type = LQ_A; - else - tbl->lq_type = LQ_G; - - if (num_of_ant(tbl->ant_type) > 1) - tbl->ant_type = ANT_A;/*FIXME:RS*/ - - tbl->is_fat = 0; - tbl->is_SGI = 0; - } - - rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type); - - /* Mask with station rate restriction */ - if (is_legacy(tbl->lq_type)) { - /* supp_rates has no CCK bits in A mode */ - if (lq_sta->band == IEEE80211_BAND_5GHZ) - rate_mask = (u16)(rate_mask & - (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE)); - else - rate_mask = (u16)(rate_mask & lq_sta->supp_rates); - } - - /* If we switched from HT to legacy, check current rate */ - if (switch_to_legacy && (rate_mask & (1 << scale_index))) { - low = scale_index; - goto out; - } - - high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask, - tbl->lq_type); - low = high_low & 0xff; - - if (low == IWL_RATE_INVALID) - low = scale_index; - -out: - return rate_n_flags_from_tbl(tbl, low, is_green); -} - -/* - * mac80211 sends us Tx status - */ -static void rs_tx_status(void *priv_rate, struct net_device *dev, - struct sk_buff *skb) -{ - int status; - u8 retries; - int rs_index, index = 0; - struct iwl4965_lq_sta *lq_sta; - struct iwl_link_quality_cmd *table; - struct sta_info *sta; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct iwl_priv *priv = (struct iwl_priv *)priv_rate; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw *hw = local_to_hw(local); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct iwl4965_rate_scale_data *window = NULL; - struct iwl4965_rate_scale_data *search_win = NULL; - u32 tx_rate; - struct iwl4965_scale_tbl_info tbl_type; - struct iwl4965_scale_tbl_info *curr_tbl, *search_tbl; - u8 active_index = 0; - __le16 fc = hdr->frame_control; - s32 tpt = 0; - - IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n"); - - if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) - return; - - /* This packet was aggregated but doesn't carry rate scale info */ - if ((info->flags & IEEE80211_TX_CTL_AMPDU) && - !(info->flags & IEEE80211_TX_STAT_AMPDU)) - return; - - retries = info->status.retry_count; - - if (retries > 15) - retries = 15; - - rcu_read_lock(); - - sta = sta_info_get(local, hdr->addr1); - - if (!sta || !sta->rate_ctrl_priv) - goto out; - - - lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; - - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && - !lq_sta->ibss_sta_added) - goto out; - - table = &lq_sta->lq; - active_index = lq_sta->active_tbl; - - curr_tbl = &(lq_sta->lq_info[active_index]); - search_tbl = &(lq_sta->lq_info[(1 - active_index)]); - window = (struct iwl4965_rate_scale_data *) - &(curr_tbl->win[0]); - search_win = (struct iwl4965_rate_scale_data *) - &(search_tbl->win[0]); - - /* - * Ignore this Tx frame response if its initial rate doesn't match - * that of latest Link Quality command. There may be stragglers - * from a previous Link Quality command, but we're no longer interested - * in those; they're either from the "active" mode while we're trying - * to check "search" mode, or a prior "search" mode after we've moved - * to a new "search" mode (which might become the new "active" mode). - */ - tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags); - rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); - if (priv->band == IEEE80211_BAND_5GHZ) - rs_index -= IWL_FIRST_OFDM_RATE; - - if ((info->tx_rate_idx < 0) || - (tbl_type.is_SGI ^ - !!(info->flags & IEEE80211_TX_CTL_SHORT_GI)) || - (tbl_type.is_fat ^ - !!(info->flags & IEEE80211_TX_CTL_40_MHZ_WIDTH)) || - (tbl_type.is_dup ^ - !!(info->flags & IEEE80211_TX_CTL_DUP_DATA)) || - (tbl_type.ant_type ^ info->antenna_sel_tx) || - (!!(tx_rate & RATE_MCS_HT_MSK) ^ - !!(info->flags & IEEE80211_TX_CTL_OFDM_HT)) || - (!!(tx_rate & RATE_MCS_GF_MSK) ^ - !!(info->flags & IEEE80211_TX_CTL_GREEN_FIELD)) || - (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != - hw->wiphy->bands[info->band]->bitrates[info->tx_rate_idx].bitrate)) { - IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate); - goto out; - } - - /* Update frame history window with "failure" for each Tx retry. */ - while (retries) { - /* Look up the rate and other info used for each tx attempt. - * Each tx attempt steps one entry deeper in the rate table. */ - tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags); - rs_get_tbl_info_from_mcs(tx_rate, priv->band, - &tbl_type, &rs_index); - - /* If type matches "search" table, - * add failure to "search" history */ - if ((tbl_type.lq_type == search_tbl->lq_type) && - (tbl_type.ant_type == search_tbl->ant_type) && - (tbl_type.is_SGI == search_tbl->is_SGI)) { - if (search_tbl->expected_tpt) - tpt = search_tbl->expected_tpt[rs_index]; - else - tpt = 0; - rs_collect_tx_data(search_win, rs_index, tpt, 1, 0); - - /* Else if type matches "current/active" table, - * add failure to "current/active" history */ - } else if ((tbl_type.lq_type == curr_tbl->lq_type) && - (tbl_type.ant_type == curr_tbl->ant_type) && - (tbl_type.is_SGI == curr_tbl->is_SGI)) { - if (curr_tbl->expected_tpt) - tpt = curr_tbl->expected_tpt[rs_index]; - else - tpt = 0; - rs_collect_tx_data(window, rs_index, tpt, 1, 0); - } - - /* If not searching for a new mode, increment failed counter - * ... this helps determine when to start searching again */ - if (lq_sta->stay_in_tbl) - lq_sta->total_failed++; - --retries; - index++; - - } - - /* - * Find (by rate) the history window to update with final Tx attempt; - * if Tx was successful first try, use original rate, - * else look up the rate that was, finally, successful. - */ - tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags); - rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); - - /* Update frame history window with "success" if Tx got ACKed ... */ - status = !!(info->flags & IEEE80211_TX_STAT_ACK); - - /* If type matches "search" table, - * add final tx status to "search" history */ - if ((tbl_type.lq_type == search_tbl->lq_type) && - (tbl_type.ant_type == search_tbl->ant_type) && - (tbl_type.is_SGI == search_tbl->is_SGI)) { - if (search_tbl->expected_tpt) - tpt = search_tbl->expected_tpt[rs_index]; - else - tpt = 0; - if (info->flags & IEEE80211_TX_CTL_AMPDU) - rs_collect_tx_data(search_win, rs_index, tpt, - info->status.ampdu_ack_len, - info->status.ampdu_ack_map); - else - rs_collect_tx_data(search_win, rs_index, tpt, - 1, status); - /* Else if type matches "current/active" table, - * add final tx status to "current/active" history */ - } else if ((tbl_type.lq_type == curr_tbl->lq_type) && - (tbl_type.ant_type == curr_tbl->ant_type) && - (tbl_type.is_SGI == curr_tbl->is_SGI)) { - if (curr_tbl->expected_tpt) - tpt = curr_tbl->expected_tpt[rs_index]; - else - tpt = 0; - if (info->flags & IEEE80211_TX_CTL_AMPDU) - rs_collect_tx_data(window, rs_index, tpt, - info->status.ampdu_ack_len, - info->status.ampdu_ack_map); - else - rs_collect_tx_data(window, rs_index, tpt, - 1, status); - } - - /* If not searching for new mode, increment success/failed counter - * ... these help determine when to start searching again */ - if (lq_sta->stay_in_tbl) { - if (info->flags & IEEE80211_TX_CTL_AMPDU) { - lq_sta->total_success += info->status.ampdu_ack_map; - lq_sta->total_failed += - (info->status.ampdu_ack_len - info->status.ampdu_ack_map); - } else { - if (status) - lq_sta->total_success++; - else - lq_sta->total_failed++; - } - } - - /* See if there's a better rate or modulation mode to try. */ - rs_rate_scale_perform(priv, dev, hdr, sta); -out: - rcu_read_unlock(); - return; -} - -/* - * Begin a period of staying with a selected modulation mode. - * Set "stay_in_tbl" flag to prevent any mode switches. - * Set frame tx success limits according to legacy vs. high-throughput, - * and reset overall (spanning all rates) tx success history statistics. - * These control how long we stay using same modulation mode before - * searching for a new mode. - */ -static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy, - struct iwl4965_lq_sta *lq_sta) -{ - IWL_DEBUG_RATE("we are staying in the same table\n"); - lq_sta->stay_in_tbl = 1; /* only place this gets set */ - if (is_legacy) { - lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT; - lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT; - lq_sta->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT; - } else { - lq_sta->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT; - lq_sta->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT; - lq_sta->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT; - } - lq_sta->table_count = 0; - lq_sta->total_failed = 0; - lq_sta->total_success = 0; -} - -/* - * Find correct throughput table for given mode of modulation - */ -static void rs_set_expected_tpt_table(struct iwl4965_lq_sta *lq_sta, - struct iwl4965_scale_tbl_info *tbl) -{ - if (is_legacy(tbl->lq_type)) { - if (!is_a_band(tbl->lq_type)) - tbl->expected_tpt = expected_tpt_G; - else - tbl->expected_tpt = expected_tpt_A; - } else if (is_siso(tbl->lq_type)) { - if (tbl->is_fat && !lq_sta->is_dup) - if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_siso40MHzSGI; - else - tbl->expected_tpt = expected_tpt_siso40MHz; - else if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_siso20MHzSGI; - else - tbl->expected_tpt = expected_tpt_siso20MHz; - - } else if (is_mimo(tbl->lq_type)) { /* FIXME:need to separate mimo2/3 */ - if (tbl->is_fat && !lq_sta->is_dup) - if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_mimo40MHzSGI; - else - tbl->expected_tpt = expected_tpt_mimo40MHz; - else if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_mimo20MHzSGI; - else - tbl->expected_tpt = expected_tpt_mimo20MHz; - } else - tbl->expected_tpt = expected_tpt_G; -} - -/* - * Find starting rate for new "search" high-throughput mode of modulation. - * Goal is to find lowest expected rate (under perfect conditions) that is - * above the current measured throughput of "active" mode, to give new mode - * a fair chance to prove itself without too many challenges. - * - * This gets called when transitioning to more aggressive modulation - * (i.e. legacy to SISO or MIMO, or SISO to MIMO), as well as less aggressive - * (i.e. MIMO to SISO). When moving to MIMO, bit rate will typically need - * to decrease to match "active" throughput. When moving from MIMO to SISO, - * bit rate will typically need to increase, but not if performance was bad. - */ -static s32 rs_get_best_rate(struct iwl_priv *priv, - struct iwl4965_lq_sta *lq_sta, - struct iwl4965_scale_tbl_info *tbl, /* "search" */ - u16 rate_mask, s8 index) -{ - /* "active" values */ - struct iwl4965_scale_tbl_info *active_tbl = - &(lq_sta->lq_info[lq_sta->active_tbl]); - s32 active_sr = active_tbl->win[index].success_ratio; - s32 active_tpt = active_tbl->expected_tpt[index]; - - /* expected "search" throughput */ - s32 *tpt_tbl = tbl->expected_tpt; - - s32 new_rate, high, low, start_hi; - u16 high_low; - s8 rate = index; - - new_rate = high = low = start_hi = IWL_RATE_INVALID; - - for (; ;) { - high_low = rs_get_adjacent_rate(priv, rate, rate_mask, - tbl->lq_type); - - low = high_low & 0xff; - high = (high_low >> 8) & 0xff; - - /* - * Lower the "search" bit rate, to give new "search" mode - * approximately the same throughput as "active" if: - * - * 1) "Active" mode has been working modestly well (but not - * great), and expected "search" throughput (under perfect - * conditions) at candidate rate is above the actual - * measured "active" throughput (but less than expected - * "active" throughput under perfect conditions). - * OR - * 2) "Active" mode has been working perfectly or very well - * and expected "search" throughput (under perfect - * conditions) at candidate rate is above expected - * "active" throughput (under perfect conditions). - */ - if ((((100 * tpt_tbl[rate]) > lq_sta->last_tpt) && - ((active_sr > IWL_RATE_DECREASE_TH) && - (active_sr <= IWL_RATE_HIGH_TH) && - (tpt_tbl[rate] <= active_tpt))) || - ((active_sr >= IWL_RATE_SCALE_SWITCH) && - (tpt_tbl[rate] > active_tpt))) { - - /* (2nd or later pass) - * If we've already tried to raise the rate, and are - * now trying to lower it, use the higher rate. */ - if (start_hi != IWL_RATE_INVALID) { - new_rate = start_hi; - break; - } - - new_rate = rate; - - /* Loop again with lower rate */ - if (low != IWL_RATE_INVALID) - rate = low; - - /* Lower rate not available, use the original */ - else - break; - - /* Else try to raise the "search" rate to match "active" */ - } else { - /* (2nd or later pass) - * If we've already tried to lower the rate, and are - * now trying to raise it, use the lower rate. */ - if (new_rate != IWL_RATE_INVALID) - break; - - /* Loop again with higher rate */ - else if (high != IWL_RATE_INVALID) { - start_hi = high; - rate = high; - - /* Higher rate not available, use the original */ - } else { - break; - } - } - } - - return new_rate; -} - -/* - * Set up search table for MIMO - */ -static int rs_switch_to_mimo2(struct iwl_priv *priv, - struct iwl4965_lq_sta *lq_sta, - struct ieee80211_conf *conf, - struct sta_info *sta, - struct iwl4965_scale_tbl_info *tbl, int index) -{ - u16 rate_mask; - s32 rate; - s8 is_green = lq_sta->is_green; - - if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || - !sta->ht_info.ht_supported) - return -1; - - if (priv->current_ht_config.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC) - return -1; - - /* Need both Tx chains/antennas to support MIMO */ - if (priv->hw_params.tx_chains_num < 2) - return -1; - - IWL_DEBUG_RATE("LQ: try to switch to MIMO2\n"); - - tbl->lq_type = LQ_MIMO2; - tbl->is_dup = lq_sta->is_dup; - tbl->action = 0; - rate_mask = lq_sta->active_mimo2_rate; - - if (priv->current_ht_config.supported_chan_width - == IWL_CHANNEL_WIDTH_40MHZ) - tbl->is_fat = 1; - else - tbl->is_fat = 0; - - /* FIXME: - don't toggle SGI here - if (tbl->is_fat) { - if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - */ - - rs_set_expected_tpt_table(lq_sta, tbl); - - rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); - - IWL_DEBUG_RATE("LQ: MIMO2 best rate %d mask %X\n", rate, rate_mask); - - if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { - IWL_DEBUG_RATE("Can't switch with index %d rate mask %x\n", - rate, rate_mask); - return -1; - } - tbl->current_rate = rate_n_flags_from_tbl(tbl, rate, is_green); - - IWL_DEBUG_RATE("LQ: Switch to new mcs %X index is green %X\n", - tbl->current_rate, is_green); - return 0; -} - -/* - * Set up search table for SISO - */ -static int rs_switch_to_siso(struct iwl_priv *priv, - struct iwl4965_lq_sta *lq_sta, - struct ieee80211_conf *conf, - struct sta_info *sta, - struct iwl4965_scale_tbl_info *tbl, int index) -{ - u16 rate_mask; - u8 is_green = lq_sta->is_green; - s32 rate; - - if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || - !sta->ht_info.ht_supported) - return -1; - - IWL_DEBUG_RATE("LQ: try to switch to SISO\n"); - - tbl->is_dup = lq_sta->is_dup; - tbl->lq_type = LQ_SISO; - tbl->action = 0; - rate_mask = lq_sta->active_siso_rate; - - if (priv->current_ht_config.supported_chan_width - == IWL_CHANNEL_WIDTH_40MHZ) - tbl->is_fat = 1; - else - tbl->is_fat = 0; - - /* FIXME: - don't toggle SGI here - if (tbl->is_fat) { - if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) - tbl->is_SGI = 1; - else - tbl->is_SGI = 0; - */ - - if (is_green) - tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/ - - rs_set_expected_tpt_table(lq_sta, tbl); - rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); - - IWL_DEBUG_RATE("LQ: get best rate %d mask %X\n", rate, rate_mask); - if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { - IWL_DEBUG_RATE("can not switch with index %d rate mask %x\n", - rate, rate_mask); - return -1; - } - tbl->current_rate = rate_n_flags_from_tbl(tbl, rate, is_green); - IWL_DEBUG_RATE("LQ: Switch to new mcs %X index is green %X\n", - tbl->current_rate, is_green); - return 0; -} - -/* - * Try to switch to new modulation mode from legacy - */ -static int rs_move_legacy_other(struct iwl_priv *priv, - struct iwl4965_lq_sta *lq_sta, - struct ieee80211_conf *conf, - struct sta_info *sta, - int index) -{ - struct iwl4965_scale_tbl_info *tbl = - &(lq_sta->lq_info[lq_sta->active_tbl]); - struct iwl4965_scale_tbl_info *search_tbl = - &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); - struct iwl4965_rate_scale_data *window = &(tbl->win[index]); - u32 sz = (sizeof(struct iwl4965_scale_tbl_info) - - (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT)); - u8 start_action = tbl->action; - u8 valid_tx_ant = priv->hw_params.valid_tx_ant; - int ret = 0; - - for (; ;) { - switch (tbl->action) { - case IWL_LEGACY_SWITCH_ANTENNA: - IWL_DEBUG_RATE("LQ: Legacy toggle Antenna\n"); - - lq_sta->action_counter++; - - /* Don't change antenna if success has been great */ - if (window->success_ratio >= IWL_RS_GOOD_RATIO) - break; - - /* Set up search table to try other antenna */ - memcpy(search_tbl, tbl, sz); - - if (rs_toggle_antenna(valid_tx_ant, - &search_tbl->current_rate, search_tbl)) { - lq_sta->search_better_tbl = 1; - goto out; - } - break; - case IWL_LEGACY_SWITCH_SISO: - IWL_DEBUG_RATE("LQ: Legacy switch to SISO\n"); - - /* Set up search table to try SISO */ - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = 0; - ret = rs_switch_to_siso(priv, lq_sta, conf, sta, - search_tbl, index); - if (!ret) { - lq_sta->search_better_tbl = 1; - lq_sta->action_counter = 0; - goto out; - } - - break; - case IWL_LEGACY_SWITCH_MIMO2: - IWL_DEBUG_RATE("LQ: Legacy switch to MIMO2\n"); - - /* Set up search table to try MIMO */ - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = 0; - search_tbl->ant_type = ANT_AB;/*FIXME:RS*/ - /*FIXME:RS:need to check ant validity*/ - ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, - search_tbl, index); - if (!ret) { - lq_sta->search_better_tbl = 1; - lq_sta->action_counter = 0; - goto out; - } - break; - } - tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) - tbl->action = IWL_LEGACY_SWITCH_ANTENNA; - - if (tbl->action == start_action) - break; - - } - return 0; - - out: - tbl->action++; - if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) - tbl->action = IWL_LEGACY_SWITCH_ANTENNA; - return 0; - -} - -/* - * Try to switch to new modulation mode from SISO - */ -static int rs_move_siso_to_other(struct iwl_priv *priv, - struct iwl4965_lq_sta *lq_sta, - struct ieee80211_conf *conf, - struct sta_info *sta, - int index) -{ - u8 is_green = lq_sta->is_green; - struct iwl4965_scale_tbl_info *tbl = - &(lq_sta->lq_info[lq_sta->active_tbl]); - struct iwl4965_scale_tbl_info *search_tbl = - &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); - struct iwl4965_rate_scale_data *window = &(tbl->win[index]); - u32 sz = (sizeof(struct iwl4965_scale_tbl_info) - - (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT)); - u8 start_action = tbl->action; - u8 valid_tx_ant = priv->hw_params.valid_tx_ant; - int ret; - - for (;;) { - lq_sta->action_counter++; - switch (tbl->action) { - case IWL_SISO_SWITCH_ANTENNA: - IWL_DEBUG_RATE("LQ: SISO toggle Antenna\n"); - if (window->success_ratio >= IWL_RS_GOOD_RATIO) - break; - - memcpy(search_tbl, tbl, sz); - if (rs_toggle_antenna(valid_tx_ant, - &search_tbl->current_rate, search_tbl)) { - lq_sta->search_better_tbl = 1; - goto out; - } - break; - case IWL_SISO_SWITCH_MIMO2: - IWL_DEBUG_RATE("LQ: SISO switch to MIMO2\n"); - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = 0; - search_tbl->ant_type = ANT_AB; /*FIXME:RS*/ - ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, - search_tbl, index); - if (!ret) { - lq_sta->search_better_tbl = 1; - goto out; - } - break; - case IWL_SISO_SWITCH_GI: - if (!tbl->is_fat && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_20MHZ)) - break; - if (tbl->is_fat && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_40MHZ)) - break; - - IWL_DEBUG_RATE("LQ: SISO toggle SGI/NGI\n"); - - memcpy(search_tbl, tbl, sz); - if (is_green) { - if (!tbl->is_SGI) - break; - else - IWL_ERROR("SGI was set in GF+SISO\n"); - } - search_tbl->is_SGI = !tbl->is_SGI; - rs_set_expected_tpt_table(lq_sta, search_tbl); - if (tbl->is_SGI) { - s32 tpt = lq_sta->last_tpt / 100; - if (tpt >= search_tbl->expected_tpt[index]) - break; - } - search_tbl->current_rate = rate_n_flags_from_tbl( - search_tbl, index, is_green); - lq_sta->search_better_tbl = 1; - goto out; - } - tbl->action++; - if (tbl->action > IWL_SISO_SWITCH_GI) - tbl->action = IWL_SISO_SWITCH_ANTENNA; - - if (tbl->action == start_action) - break; - } - return 0; - - out: - tbl->action++; - if (tbl->action > IWL_SISO_SWITCH_GI) - tbl->action = IWL_SISO_SWITCH_ANTENNA; - return 0; -} - -/* - * Try to switch to new modulation mode from MIMO - */ -static int rs_move_mimo_to_other(struct iwl_priv *priv, - struct iwl4965_lq_sta *lq_sta, - struct ieee80211_conf *conf, - struct sta_info *sta, - int index) -{ - s8 is_green = lq_sta->is_green; - struct iwl4965_scale_tbl_info *tbl = - &(lq_sta->lq_info[lq_sta->active_tbl]); - struct iwl4965_scale_tbl_info *search_tbl = - &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); - u32 sz = (sizeof(struct iwl4965_scale_tbl_info) - - (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT)); - u8 start_action = tbl->action; - /*u8 valid_tx_ant = priv->hw_params.valid_tx_ant;*/ - int ret; - - for (;;) { - lq_sta->action_counter++; - switch (tbl->action) { - case IWL_MIMO_SWITCH_ANTENNA_A: - case IWL_MIMO_SWITCH_ANTENNA_B: - IWL_DEBUG_RATE("LQ: MIMO2 switch to SISO\n"); - - /* Set up new search table for SISO */ - memcpy(search_tbl, tbl, sz); - - /*FIXME:RS:need to check ant validity + C*/ - if (tbl->action == IWL_MIMO_SWITCH_ANTENNA_A) - search_tbl->ant_type = ANT_A; - else - search_tbl->ant_type = ANT_B; - - ret = rs_switch_to_siso(priv, lq_sta, conf, sta, - search_tbl, index); - if (!ret) { - lq_sta->search_better_tbl = 1; - goto out; - } - break; - - case IWL_MIMO_SWITCH_GI: - if (!tbl->is_fat && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_20MHZ)) - break; - if (tbl->is_fat && - !(priv->current_ht_config.sgf & - HT_SHORT_GI_40MHZ)) - break; - - IWL_DEBUG_RATE("LQ: MIMO toggle SGI/NGI\n"); - - /* Set up new search table for MIMO */ - memcpy(search_tbl, tbl, sz); - search_tbl->is_SGI = !tbl->is_SGI; - rs_set_expected_tpt_table(lq_sta, search_tbl); - /* - * If active table already uses the fastest possible - * modulation (dual stream with short guard interval), - * and it's working well, there's no need to look - * for a better type of modulation! - */ - if (tbl->is_SGI) { - s32 tpt = lq_sta->last_tpt / 100; - if (tpt >= search_tbl->expected_tpt[index]) - break; - } - search_tbl->current_rate = rate_n_flags_from_tbl( - search_tbl, index, is_green); - lq_sta->search_better_tbl = 1; - goto out; - - } - tbl->action++; - if (tbl->action > IWL_MIMO_SWITCH_GI) - tbl->action = IWL_MIMO_SWITCH_ANTENNA_A; - - if (tbl->action == start_action) - break; - } - - return 0; - out: - tbl->action++; - if (tbl->action > IWL_MIMO_SWITCH_GI) - tbl->action = IWL_MIMO_SWITCH_ANTENNA_A; - return 0; - -} - -/* - * Check whether we should continue using same modulation mode, or - * begin search for a new mode, based on: - * 1) # tx successes or failures while using this mode - * 2) # times calling this function - * 3) elapsed time in this mode (not used, for now) - */ -static void rs_stay_in_table(struct iwl4965_lq_sta *lq_sta) -{ - struct iwl4965_scale_tbl_info *tbl; - int i; - int active_tbl; - int flush_interval_passed = 0; - struct iwl_priv *priv; - - priv = lq_sta->drv; - active_tbl = lq_sta->active_tbl; - - tbl = &(lq_sta->lq_info[active_tbl]); - - /* If we've been disallowing search, see if we should now allow it */ - if (lq_sta->stay_in_tbl) { - - /* Elapsed time using current modulation mode */ - if (lq_sta->flush_timer) - flush_interval_passed = - time_after(jiffies, - (unsigned long)(lq_sta->flush_timer + - IWL_RATE_SCALE_FLUSH_INTVL)); - - /* - * Check if we should allow search for new modulation mode. - * If many frames have failed or succeeded, or we've used - * this same modulation for a long time, allow search, and - * reset history stats that keep track of whether we should - * allow a new search. Also (below) reset all bitmaps and - * stats in active history. - */ - if ((lq_sta->total_failed > lq_sta->max_failure_limit) || - (lq_sta->total_success > lq_sta->max_success_limit) || - ((!lq_sta->search_better_tbl) && (lq_sta->flush_timer) - && (flush_interval_passed))) { - IWL_DEBUG_RATE("LQ: stay is expired %d %d %d\n:", - lq_sta->total_failed, - lq_sta->total_success, - flush_interval_passed); - - /* Allow search for new mode */ - lq_sta->stay_in_tbl = 0; /* only place reset */ - lq_sta->total_failed = 0; - lq_sta->total_success = 0; - lq_sta->flush_timer = 0; - - /* - * Else if we've used this modulation mode enough repetitions - * (regardless of elapsed time or success/failure), reset - * history bitmaps and rate-specific stats for all rates in - * active table. - */ - } else { - lq_sta->table_count++; - if (lq_sta->table_count >= - lq_sta->table_count_limit) { - lq_sta->table_count = 0; - - IWL_DEBUG_RATE("LQ: stay in table clear win\n"); - for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window( - &(tbl->win[i])); - } - } - - /* If transitioning to allow "search", reset all history - * bitmaps and stats in active table (this will become the new - * "search" table). */ - if (!lq_sta->stay_in_tbl) { - for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window(&(tbl->win[i])); - } - } -} - -/* - * Do rate scaling and search for new modulation mode. - */ -static void rs_rate_scale_perform(struct iwl_priv *priv, - struct net_device *dev, - struct ieee80211_hdr *hdr, - struct sta_info *sta) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw *hw = local_to_hw(local); - struct ieee80211_conf *conf = &hw->conf; - int low = IWL_RATE_INVALID; - int high = IWL_RATE_INVALID; - int index; - int i; - struct iwl4965_rate_scale_data *window = NULL; - int current_tpt = IWL_INVALID_VALUE; - int low_tpt = IWL_INVALID_VALUE; - int high_tpt = IWL_INVALID_VALUE; - u32 fail_count; - s8 scale_action = 0; - __le16 fc; - u16 rate_mask; - u8 update_lq = 0; - struct iwl4965_lq_sta *lq_sta; - struct iwl4965_scale_tbl_info *tbl, *tbl1; - u16 rate_scale_index_msk = 0; - u32 rate; - u8 is_green = 0; - u8 active_tbl = 0; - u8 done_search = 0; - u16 high_low; - s32 sr; - u8 tid = MAX_TID_COUNT; - - IWL_DEBUG_RATE("rate scale calculate new rate for skb\n"); - - fc = hdr->frame_control; - if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) { - /* Send management frames and broadcast/multicast data using - * lowest rate. */ - /* TODO: this could probably be improved.. */ - return; - } - - if (!sta || !sta->rate_ctrl_priv) - return; - - lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; - - tid = rs_tl_add_packet(lq_sta, hdr); - - /* - * Select rate-scale / modulation-mode table to work with in - * the rest of this function: "search" if searching for better - * modulation mode, or "active" if doing rate scaling within a mode. - */ - if (!lq_sta->search_better_tbl) - active_tbl = lq_sta->active_tbl; - else - active_tbl = 1 - lq_sta->active_tbl; - - tbl = &(lq_sta->lq_info[active_tbl]); - is_green = lq_sta->is_green; - - /* current tx rate */ - index = sta->last_txrate_idx; - - IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index, - tbl->lq_type); - - /* rates available for this association, and for modulation mode */ - rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type); - - IWL_DEBUG_RATE("mask 0x%04X \n", rate_mask); - - /* mask with station rate restriction */ - if (is_legacy(tbl->lq_type)) { - if (lq_sta->band == IEEE80211_BAND_5GHZ) - /* supp_rates has no CCK bits in A mode */ - rate_scale_index_msk = (u16) (rate_mask & - (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE)); - else - rate_scale_index_msk = (u16) (rate_mask & - lq_sta->supp_rates); - - } else - rate_scale_index_msk = rate_mask; - - if (!rate_scale_index_msk) - rate_scale_index_msk = rate_mask; - - if (!((1 << index) & rate_scale_index_msk)) { - IWL_ERROR("Current Rate is not valid\n"); - return; - } - - /* Get expected throughput table and history window for current rate */ - if (!tbl->expected_tpt) { - IWL_ERROR("tbl->expected_tpt is NULL\n"); - return; - } - - window = &(tbl->win[index]); - - /* - * If there is not enough history to calculate actual average - * throughput, keep analyzing results of more tx frames, without - * changing rate or mode (bypass most of the rest of this function). - * Set up new rate table in uCode only if old rate is not supported - * in current association (use new rate found above). - */ - fail_count = window->counter - window->success_counter; - if ((fail_count < IWL_RATE_MIN_FAILURE_TH) && - (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) { - IWL_DEBUG_RATE("LQ: still below TH. succ=%d total=%d " - "for index %d\n", - window->success_counter, window->counter, index); - - /* Can't calculate this yet; not enough history */ - window->average_tpt = IWL_INVALID_VALUE; - - /* Should we stay with this modulation mode, - * or search for a new one? */ - rs_stay_in_table(lq_sta); - - goto out; - - /* Else we have enough samples; calculate estimate of - * actual average throughput */ - } else { - /*FIXME:RS remove this else if we don't get this error*/ - if (window->average_tpt != ((window->success_ratio * - tbl->expected_tpt[index] + 64) / 128)) { - IWL_ERROR("expected_tpt should have been calculated" - " by now\n"); - window->average_tpt = ((window->success_ratio * - tbl->expected_tpt[index] + 64) / 128); - } - } - - /* If we are searching for better modulation mode, check success. */ - if (lq_sta->search_better_tbl) { - - /* If good success, continue using the "search" mode; - * no need to send new link quality command, since we're - * continuing to use the setup that we've been trying. */ - if (window->average_tpt > lq_sta->last_tpt) { - - IWL_DEBUG_RATE("LQ: SWITCHING TO CURRENT TABLE " - "suc=%d cur-tpt=%d old-tpt=%d\n", - window->success_ratio, - window->average_tpt, - lq_sta->last_tpt); - - if (!is_legacy(tbl->lq_type)) - lq_sta->enable_counter = 1; - - /* Swap tables; "search" becomes "active" */ - lq_sta->active_tbl = active_tbl; - current_tpt = window->average_tpt; - - /* Else poor success; go back to mode in "active" table */ - } else { - - IWL_DEBUG_RATE("LQ: GOING BACK TO THE OLD TABLE " - "suc=%d cur-tpt=%d old-tpt=%d\n", - window->success_ratio, - window->average_tpt, - lq_sta->last_tpt); - - /* Nullify "search" table */ - tbl->lq_type = LQ_NONE; - - /* Revert to "active" table */ - active_tbl = lq_sta->active_tbl; - tbl = &(lq_sta->lq_info[active_tbl]); - - /* Revert to "active" rate and throughput info */ - index = iwl_hwrate_to_plcp_idx(tbl->current_rate); - current_tpt = lq_sta->last_tpt; - - /* Need to set up a new rate table in uCode */ - update_lq = 1; - } - - /* Either way, we've made a decision; modulation mode - * search is done, allow rate adjustment next time. */ - lq_sta->search_better_tbl = 0; - done_search = 1; /* Don't switch modes below! */ - goto lq_update; - } - - /* (Else) not in search of better modulation mode, try for better - * starting rate, while staying in this mode. */ - high_low = rs_get_adjacent_rate(priv, index, rate_scale_index_msk, - tbl->lq_type); - low = high_low & 0xff; - high = (high_low >> 8) & 0xff; - - sr = window->success_ratio; - - /* Collect measured throughputs for current and adjacent rates */ - current_tpt = window->average_tpt; - if (low != IWL_RATE_INVALID) - low_tpt = tbl->win[low].average_tpt; - if (high != IWL_RATE_INVALID) - high_tpt = tbl->win[high].average_tpt; - - scale_action = 0; - - /* Too many failures, decrease rate */ - if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) { - IWL_DEBUG_RATE("decrease rate because of low success_ratio\n"); - scale_action = -1; - - /* No throughput measured yet for adjacent rates; try increase. */ - } else if ((low_tpt == IWL_INVALID_VALUE) && - (high_tpt == IWL_INVALID_VALUE)) { - - if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH) - scale_action = 1; - else if (low != IWL_RATE_INVALID) - scale_action = -1; - } - - /* Both adjacent throughputs are measured, but neither one has better - * throughput; we're using the best rate, don't change it! */ - else if ((low_tpt != IWL_INVALID_VALUE) && - (high_tpt != IWL_INVALID_VALUE) && - (low_tpt < current_tpt) && - (high_tpt < current_tpt)) - scale_action = 0; - - /* At least one adjacent rate's throughput is measured, - * and may have better performance. */ - else { - /* Higher adjacent rate's throughput is measured */ - if (high_tpt != IWL_INVALID_VALUE) { - /* Higher rate has better throughput */ - if (high_tpt > current_tpt && - sr >= IWL_RATE_INCREASE_TH) { - scale_action = 1; - } else { - IWL_DEBUG_RATE - ("decrease rate because of high tpt\n"); - scale_action = -1; - } - - /* Lower adjacent rate's throughput is measured */ - } else if (low_tpt != IWL_INVALID_VALUE) { - /* Lower rate has better throughput */ - if (low_tpt > current_tpt) { - IWL_DEBUG_RATE - ("decrease rate because of low tpt\n"); - scale_action = -1; - } else if (sr >= IWL_RATE_INCREASE_TH) { - scale_action = 1; - } - } - } - - /* Sanity check; asked for decrease, but success rate or throughput - * has been good at old rate. Don't change it. */ - if ((scale_action == -1) && (low != IWL_RATE_INVALID) && - ((sr > IWL_RATE_HIGH_TH) || - (current_tpt > (100 * tbl->expected_tpt[low])))) - scale_action = 0; - - switch (scale_action) { - case -1: - /* Decrease starting rate, update uCode's rate table */ - if (low != IWL_RATE_INVALID) { - update_lq = 1; - index = low; - } - break; - case 1: - /* Increase starting rate, update uCode's rate table */ - if (high != IWL_RATE_INVALID) { - update_lq = 1; - index = high; - } - - break; - case 0: - /* No change */ - default: - break; - } - - IWL_DEBUG_RATE("choose rate scale index %d action %d low %d " - "high %d type %d\n", - index, scale_action, low, high, tbl->lq_type); - -lq_update: - /* Replace uCode's rate table for the destination station. */ - if (update_lq) { - rate = rate_n_flags_from_tbl(tbl, index, is_green); - rs_fill_link_cmd(priv, lq_sta, rate); - iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); - } - - /* Should we stay with this modulation mode, or search for a new one? */ - rs_stay_in_table(lq_sta); - - /* - * Search for new modulation mode if we're: - * 1) Not changing rates right now - * 2) Not just finishing up a search - * 3) Allowing a new search - */ - if (!update_lq && !done_search && !lq_sta->stay_in_tbl && window->counter) { - /* Save current throughput to compare with "search" throughput*/ - lq_sta->last_tpt = current_tpt; - - /* Select a new "search" modulation mode to try. - * If one is found, set up the new "search" table. */ - if (is_legacy(tbl->lq_type)) - rs_move_legacy_other(priv, lq_sta, conf, sta, index); - else if (is_siso(tbl->lq_type)) - rs_move_siso_to_other(priv, lq_sta, conf, sta, index); - else - rs_move_mimo_to_other(priv, lq_sta, conf, sta, index); - - /* If new "search" mode was selected, set up in uCode table */ - if (lq_sta->search_better_tbl) { - /* Access the "search" table, clear its history. */ - tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); - for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window(&(tbl->win[i])); - - /* Use new "search" start rate */ - index = iwl_hwrate_to_plcp_idx(tbl->current_rate); - - IWL_DEBUG_RATE("Switch current mcs: %X index: %d\n", - tbl->current_rate, index); - rs_fill_link_cmd(priv, lq_sta, tbl->current_rate); - iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); - } - - /* If the "active" (non-search) mode was legacy, - * and we've tried switching antennas, - * but we haven't been able to try HT modes (not available), - * stay with best antenna legacy modulation for a while - * before next round of mode comparisons. */ - tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); - if (is_legacy(tbl1->lq_type) && - (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) && - (lq_sta->action_counter >= 1)) { - lq_sta->action_counter = 0; - IWL_DEBUG_RATE("LQ: STAY in legacy table\n"); - rs_set_stay_in_table(priv, 1, lq_sta); - } - - /* If we're in an HT mode, and all 3 mode switch actions - * have been tried and compared, stay in this best modulation - * mode for a while before next round of mode comparisons. */ - if (lq_sta->enable_counter && - (lq_sta->action_counter >= IWL_ACTION_LIMIT)) { - if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && - (lq_sta->tx_agg_tid_en & (1 << tid)) && - (tid != MAX_TID_COUNT)) { - IWL_DEBUG_RATE("try to aggregate tid %d\n", tid); - rs_tl_turn_on_agg(priv, tid, lq_sta, sta); - } - lq_sta->action_counter = 0; - rs_set_stay_in_table(priv, 0, lq_sta); - } - - /* - * Else, don't search for a new modulation mode. - * Put new timestamp in stay-in-modulation-mode flush timer if: - * 1) Not changing rates right now - * 2) Not just finishing up a search - * 3) flush timer is empty - */ - } else { - if ((!update_lq) && (!done_search) && (!lq_sta->flush_timer)) - lq_sta->flush_timer = jiffies; - } - -out: - tbl->current_rate = rate_n_flags_from_tbl(tbl, index, is_green); - i = index; - sta->last_txrate_idx = i; - - /* sta->txrate_idx is an index to A mode rates which start - * at IWL_FIRST_OFDM_RATE - */ - if (lq_sta->band == IEEE80211_BAND_5GHZ) - sta->txrate_idx = i - IWL_FIRST_OFDM_RATE; - else - sta->txrate_idx = i; - - return; -} - - -static void rs_initialize_lq(struct iwl_priv *priv, - struct ieee80211_conf *conf, - struct sta_info *sta) -{ - struct iwl4965_lq_sta *lq_sta; - struct iwl4965_scale_tbl_info *tbl; - int rate_idx; - int i; - u32 rate; - u8 use_green = rs_use_green(priv, conf); - u8 active_tbl = 0; - u8 valid_tx_ant; - - if (!sta || !sta->rate_ctrl_priv) - goto out; - - lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; - i = sta->last_txrate_idx; - - if ((lq_sta->lq.sta_id == 0xff) && - (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)) - goto out; - - valid_tx_ant = priv->hw_params.valid_tx_ant; - - if (!lq_sta->search_better_tbl) - active_tbl = lq_sta->active_tbl; - else - active_tbl = 1 - lq_sta->active_tbl; - - tbl = &(lq_sta->lq_info[active_tbl]); - - if ((i < 0) || (i >= IWL_RATE_COUNT)) - i = 0; - - /* FIXME:RS: This is also wrong in 4965 */ - rate = iwl_rates[i].plcp; - rate |= RATE_MCS_ANT_B_MSK; - rate &= ~RATE_MCS_ANT_A_MSK; - - if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE) - rate |= RATE_MCS_CCK_MSK; - - tbl->ant_type = ANT_B; - rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx); - if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type)) - rs_toggle_antenna(valid_tx_ant, &rate, tbl); - - rate = rate_n_flags_from_tbl(tbl, rate_idx, use_green); - tbl->current_rate = rate; - rs_set_expected_tpt_table(lq_sta, tbl); - rs_fill_link_cmd(NULL, lq_sta, rate); - iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); - out: - return; -} - -static void rs_get_rate(void *priv_rate, struct net_device *dev, - struct ieee80211_supported_band *sband, - struct sk_buff *skb, - struct rate_selection *sel) -{ - - int i; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_conf *conf = &local->hw.conf; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct sta_info *sta; - __le16 fc; - struct iwl_priv *priv = (struct iwl_priv *)priv_rate; - struct iwl4965_lq_sta *lq_sta; - - IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); - - rcu_read_lock(); - - sta = sta_info_get(local, hdr->addr1); - - /* Send management frames and broadcast/multicast data using lowest - * rate. */ - fc = hdr->frame_control; - if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || - !sta || !sta->rate_ctrl_priv) { - sel->rate_idx = rate_lowest_index(local, sband, sta); - goto out; - } - - lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; - i = sta->last_txrate_idx; - - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && - !lq_sta->ibss_sta_added) { - u8 sta_id = iwl_find_station(priv, hdr->addr1); - DECLARE_MAC_BUF(mac); - - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_RATE("LQ: ADD station %s\n", - print_mac(mac, hdr->addr1)); - sta_id = iwl_add_station_flags(priv, hdr->addr1, - 0, CMD_ASYNC, NULL); - } - if ((sta_id != IWL_INVALID_STATION)) { - lq_sta->lq.sta_id = sta_id; - lq_sta->lq.rs_table[0].rate_n_flags = 0; - lq_sta->ibss_sta_added = 1; - rs_initialize_lq(priv, conf, sta); - } - } - - if ((i < 0) || (i > IWL_RATE_COUNT)) { - sel->rate_idx = rate_lowest_index(local, sband, sta); - goto out; - } - - if (sband->band == IEEE80211_BAND_5GHZ) - i -= IWL_FIRST_OFDM_RATE; - sel->rate_idx = i; -out: - rcu_read_unlock(); -} - -static void *rs_alloc_sta(void *priv_rate, gfp_t gfp) -{ - struct iwl4965_lq_sta *lq_sta; - struct iwl_priv *priv; - int i, j; - - priv = (struct iwl_priv *)priv_rate; - IWL_DEBUG_RATE("create station rate scale window\n"); - - lq_sta = kzalloc(sizeof(struct iwl4965_lq_sta), gfp); - - if (lq_sta == NULL) - return NULL; - lq_sta->lq.sta_id = 0xff; - - - for (j = 0; j < LQ_SIZE; j++) - for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i])); - - return lq_sta; -} - -static void rs_rate_init(void *priv_rate, void *priv_sta, - struct ieee80211_local *local, - struct sta_info *sta) -{ - int i, j; - struct ieee80211_conf *conf = &local->hw.conf; - struct ieee80211_supported_band *sband; - struct iwl_priv *priv = (struct iwl_priv *)priv_rate; - struct iwl4965_lq_sta *lq_sta = priv_sta; - - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - lq_sta->flush_timer = 0; - lq_sta->supp_rates = sta->supp_rates[sband->band]; - sta->txrate_idx = 3; - for (j = 0; j < LQ_SIZE; j++) - for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i])); - - IWL_DEBUG_RATE("LQ: *** rate scale global init ***\n"); - /* TODO: what is a good starting rate for STA? About middle? Maybe not - * the lowest or the highest rate.. Could consider using RSSI from - * previous packets? Need to have IEEE 802.1X auth succeed immediately - * after assoc.. */ - - lq_sta->ibss_sta_added = 0; - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { - u8 sta_id = iwl_find_station(priv, sta->addr); - DECLARE_MAC_BUF(mac); - - /* for IBSS the call are from tasklet */ - IWL_DEBUG_RATE("LQ: ADD station %s\n", - print_mac(mac, sta->addr)); - - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_RATE("LQ: ADD station %s\n", - print_mac(mac, sta->addr)); - sta_id = iwl_add_station_flags(priv, sta->addr, - 0, CMD_ASYNC, NULL); - } - if ((sta_id != IWL_INVALID_STATION)) { - lq_sta->lq.sta_id = sta_id; - lq_sta->lq.rs_table[0].rate_n_flags = 0; - } - /* FIXME: this is w/a remove it later */ - priv->assoc_station_added = 1; - } - - /* Find highest tx rate supported by hardware and destination station */ - for (i = 0; i < sband->n_bitrates; i++) - if (sta->supp_rates[sband->band] & BIT(i)) - sta->txrate_idx = i; - - sta->last_txrate_idx = sta->txrate_idx; - /* WTF is with this bogus comment? A doesn't have cck rates */ - /* For MODE_IEEE80211A, cck rates are at end of rate table */ - if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) - sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; - - lq_sta->is_dup = 0; - lq_sta->is_green = rs_use_green(priv, conf); - lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000); - lq_sta->active_rate_basic = priv->active_rate_basic; - lq_sta->band = priv->band; - /* - * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), - * supp_rates[] does not; shift to convert format, force 9 MBits off. - */ - lq_sta->active_siso_rate = conf->ht_conf.supp_mcs_set[0] << 1; - lq_sta->active_siso_rate |= conf->ht_conf.supp_mcs_set[0] & 0x1; - lq_sta->active_siso_rate &= ~((u16)0x2); - lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; - - /* Same here */ - lq_sta->active_mimo2_rate = conf->ht_conf.supp_mcs_set[1] << 1; - lq_sta->active_mimo2_rate |= conf->ht_conf.supp_mcs_set[1] & 0x1; - lq_sta->active_mimo2_rate &= ~((u16)0x2); - lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; - - lq_sta->active_mimo3_rate = conf->ht_conf.supp_mcs_set[2] << 1; - lq_sta->active_mimo3_rate |= conf->ht_conf.supp_mcs_set[2] & 0x1; - lq_sta->active_mimo3_rate &= ~((u16)0x2); - lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; - - IWL_DEBUG_RATE("SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n", - lq_sta->active_siso_rate, - lq_sta->active_mimo2_rate, - lq_sta->active_mimo3_rate); - - /* These values will be overriden later */ - lq_sta->lq.general_params.single_stream_ant_msk = ANT_A; - lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB; - - /* as default allow aggregation for all tids */ - lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; - lq_sta->drv = priv; - - rs_initialize_lq(priv, conf, sta); -} - -static void rs_fill_link_cmd(const struct iwl_priv *priv, - struct iwl4965_lq_sta *lq_sta, - u32 new_rate) -{ - struct iwl4965_scale_tbl_info tbl_type; - int index = 0; - int rate_idx; - int repeat_rate = 0; - u8 ant_toggle_cnt = 0; - u8 use_ht_possible = 1; - u8 valid_tx_ant = 0; - struct iwl_link_quality_cmd *lq_cmd = &lq_sta->lq; - - /* Override starting rate (index 0) if needed for debug purposes */ - rs_dbgfs_set_mcs(lq_sta, &new_rate, index); - - /* Interpret new_rate (rate_n_flags) */ - memset(&tbl_type, 0, sizeof(tbl_type)); - rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, - &tbl_type, &rate_idx); - - /* How many times should we repeat the initial rate? */ - if (is_legacy(tbl_type.lq_type)) { - ant_toggle_cnt = 1; - repeat_rate = IWL_NUMBER_TRY; - } else { - repeat_rate = IWL_HT_NUMBER_TRY; - } - - lq_cmd->general_params.mimo_delimiter = - is_mimo(tbl_type.lq_type) ? 1 : 0; - - /* Fill 1st table entry (index 0) */ - lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate); - - if (num_of_ant(tbl_type.ant_type) == 1) { - lq_cmd->general_params.single_stream_ant_msk = - tbl_type.ant_type; - } else if (num_of_ant(tbl_type.ant_type) == 2) { - lq_cmd->general_params.dual_stream_ant_msk = - tbl_type.ant_type; - } /* otherwise we don't modify the existing value */ - - index++; - repeat_rate--; - - if (priv) - valid_tx_ant = priv->hw_params.valid_tx_ant; - - /* Fill rest of rate table */ - while (index < LINK_QUAL_MAX_RETRY_NUM) { - /* Repeat initial/next rate. - * For legacy IWL_NUMBER_TRY == 1, this loop will not execute. - * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */ - while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) { - if (is_legacy(tbl_type.lq_type)) { - if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) - ant_toggle_cnt++; - else if (priv && - rs_toggle_antenna(valid_tx_ant, - &new_rate, &tbl_type)) - ant_toggle_cnt = 1; -} - - /* Override next rate if needed for debug purposes */ - rs_dbgfs_set_mcs(lq_sta, &new_rate, index); - - /* Fill next table entry */ - lq_cmd->rs_table[index].rate_n_flags = - cpu_to_le32(new_rate); - repeat_rate--; - index++; - } - - rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type, - &rate_idx); - - /* Indicate to uCode which entries might be MIMO. - * If initial rate was MIMO, this will finally end up - * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */ - if (is_mimo(tbl_type.lq_type)) - lq_cmd->general_params.mimo_delimiter = index; - - /* Get next rate */ - new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx, - use_ht_possible); - - /* How many times should we repeat the next rate? */ - if (is_legacy(tbl_type.lq_type)) { - if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) - ant_toggle_cnt++; - else if (priv && - rs_toggle_antenna(valid_tx_ant, - &new_rate, &tbl_type)) - ant_toggle_cnt = 1; - - repeat_rate = IWL_NUMBER_TRY; - } else { - repeat_rate = IWL_HT_NUMBER_TRY; - } - - /* Don't allow HT rates after next pass. - * rs_get_lower_rate() will change type to LQ_A or LQ_G. */ - use_ht_possible = 0; - - /* Override next rate if needed for debug purposes */ - rs_dbgfs_set_mcs(lq_sta, &new_rate, index); - - /* Fill next table entry */ - lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate); - - index++; - repeat_rate--; - } - - lq_cmd->agg_params.agg_frame_cnt_limit = 64; - lq_cmd->agg_params.agg_dis_start_th = 3; - lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000); -} - -static void *rs_alloc(struct ieee80211_local *local) -{ - return local->hw.priv; -} -/* rate scale requires free function to be implemented */ -static void rs_free(void *priv_rate) -{ - return; -} - -static void rs_clear(void *priv_rate) -{ - struct iwl_priv *priv = (struct iwl_priv *) priv_rate; - - IWL_DEBUG_RATE("enter\n"); - - /* TODO - add rate scale state reset */ - - IWL_DEBUG_RATE("leave\n"); -} - -static void rs_free_sta(void *priv_rate, void *priv_sta) -{ - struct iwl4965_lq_sta *lq_sta = priv_sta; - struct iwl_priv *priv; - - priv = (struct iwl_priv *)priv_rate; - IWL_DEBUG_RATE("enter\n"); - kfree(lq_sta); - IWL_DEBUG_RATE("leave\n"); -} - - -#ifdef CONFIG_MAC80211_DEBUGFS -static int open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} -static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta, - u32 *rate_n_flags, int index) -{ - struct iwl_priv *priv; - - priv = lq_sta->drv; - if (lq_sta->dbg_fixed_rate) { - if (index < 12) { - *rate_n_flags = lq_sta->dbg_fixed_rate; - } else { - if (lq_sta->band == IEEE80211_BAND_5GHZ) - *rate_n_flags = 0x800D; - else - *rate_n_flags = 0x820A; - } - IWL_DEBUG_RATE("Fixed rate ON\n"); - } else { - IWL_DEBUG_RATE("Fixed rate OFF\n"); - } -} - -static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, - const char __user *user_buf, size_t count, loff_t *ppos) -{ - struct iwl4965_lq_sta *lq_sta = file->private_data; - struct iwl_priv *priv; - char buf[64]; - int buf_size; - u32 parsed_rate; - - priv = lq_sta->drv; - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - - if (sscanf(buf, "%x", &parsed_rate) == 1) - lq_sta->dbg_fixed_rate = parsed_rate; - else - lq_sta->dbg_fixed_rate = 0; - - lq_sta->active_legacy_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */ - lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ - lq_sta->active_mimo2_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ - lq_sta->active_mimo3_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ - - IWL_DEBUG_RATE("sta_id %d rate 0x%X\n", - lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate); - - if (lq_sta->dbg_fixed_rate) { - rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate); - iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC); - } - - return count; -} - -static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, - char __user *user_buf, size_t count, loff_t *ppos) -{ - char buff[1024]; - int desc = 0; - int i = 0; - - struct iwl4965_lq_sta *lq_sta = file->private_data; - - desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id); - desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n", - lq_sta->total_failed, lq_sta->total_success, - lq_sta->active_legacy_rate); - desc += sprintf(buff+desc, "fixed rate 0x%X\n", - lq_sta->dbg_fixed_rate); - desc += sprintf(buff+desc, "general:" - "flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n", - lq_sta->lq.general_params.flags, - lq_sta->lq.general_params.mimo_delimiter, - lq_sta->lq.general_params.single_stream_ant_msk, - lq_sta->lq.general_params.dual_stream_ant_msk); - - desc += sprintf(buff+desc, "agg:" - "time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n", - le16_to_cpu(lq_sta->lq.agg_params.agg_time_limit), - lq_sta->lq.agg_params.agg_dis_start_th, - lq_sta->lq.agg_params.agg_frame_cnt_limit); - - desc += sprintf(buff+desc, - "Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n", - lq_sta->lq.general_params.start_rate_index[0], - lq_sta->lq.general_params.start_rate_index[1], - lq_sta->lq.general_params.start_rate_index[2], - lq_sta->lq.general_params.start_rate_index[3]); - - - for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) - desc += sprintf(buff+desc, " rate[%d] 0x%X\n", - i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags)); - - return simple_read_from_buffer(user_buf, count, ppos, buff, desc); -} - -static const struct file_operations rs_sta_dbgfs_scale_table_ops = { - .write = rs_sta_dbgfs_scale_table_write, - .read = rs_sta_dbgfs_scale_table_read, - .open = open_file_generic, -}; -static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, - char __user *user_buf, size_t count, loff_t *ppos) -{ - char buff[1024]; - int desc = 0; - int i, j; - - struct iwl4965_lq_sta *lq_sta = file->private_data; - for (i = 0; i < LQ_SIZE; i++) { - desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n" - "rate=0x%X\n", - lq_sta->active_tbl == i?"*":"x", - lq_sta->lq_info[i].lq_type, - lq_sta->lq_info[i].is_SGI, - lq_sta->lq_info[i].is_fat, - lq_sta->lq_info[i].is_dup, - lq_sta->lq_info[i].current_rate); - for (j = 0; j < IWL_RATE_COUNT; j++) { - desc += sprintf(buff+desc, - "counter=%d success=%d %%=%d\n", - lq_sta->lq_info[i].win[j].counter, - lq_sta->lq_info[i].win[j].success_counter, - lq_sta->lq_info[i].win[j].success_ratio); - } - } - return simple_read_from_buffer(user_buf, count, ppos, buff, desc); -} - -static const struct file_operations rs_sta_dbgfs_stats_table_ops = { - .read = rs_sta_dbgfs_stats_table_read, - .open = open_file_generic, -}; - -static void rs_add_debugfs(void *priv, void *priv_sta, - struct dentry *dir) -{ - struct iwl4965_lq_sta *lq_sta = priv_sta; - lq_sta->rs_sta_dbgfs_scale_table_file = - debugfs_create_file("rate_scale_table", 0600, dir, - lq_sta, &rs_sta_dbgfs_scale_table_ops); - lq_sta->rs_sta_dbgfs_stats_table_file = - debugfs_create_file("rate_stats_table", 0600, dir, - lq_sta, &rs_sta_dbgfs_stats_table_ops); - lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file = - debugfs_create_u8("tx_agg_tid_enable", 0600, dir, - &lq_sta->tx_agg_tid_en); - -} - -static void rs_remove_debugfs(void *priv, void *priv_sta) -{ - struct iwl4965_lq_sta *lq_sta = priv_sta; - debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file); - debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file); - debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file); -} -#endif - -static struct rate_control_ops rs_ops = { - .module = NULL, - .name = RS_NAME, - .tx_status = rs_tx_status, - .get_rate = rs_get_rate, - .rate_init = rs_rate_init, - .clear = rs_clear, - .alloc = rs_alloc, - .free = rs_free, - .alloc_sta = rs_alloc_sta, - .free_sta = rs_free_sta, -#ifdef CONFIG_MAC80211_DEBUGFS - .add_sta_debugfs = rs_add_debugfs, - .remove_sta_debugfs = rs_remove_debugfs, -#endif -}; - -int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct iwl_priv *priv = hw->priv; - struct iwl4965_lq_sta *lq_sta; - struct sta_info *sta; - int cnt = 0, i; - u32 samples = 0, success = 0, good = 0; - unsigned long now = jiffies; - u32 max_time = 0; - u8 lq_type, antenna; - - rcu_read_lock(); - - sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); - if (!sta || !sta->rate_ctrl_priv) { - if (sta) - IWL_DEBUG_RATE("leave - no private rate data!\n"); - else - IWL_DEBUG_RATE("leave - no station!\n"); - rcu_read_unlock(); - return sprintf(buf, "station %d not found\n", sta_id); - } - - lq_sta = (void *)sta->rate_ctrl_priv; - - lq_type = lq_sta->lq_info[lq_sta->active_tbl].lq_type; - antenna = lq_sta->lq_info[lq_sta->active_tbl].ant_type; - - if (is_legacy(lq_type)) - i = IWL_RATE_54M_INDEX; - else - i = IWL_RATE_60M_INDEX; - while (1) { - u64 mask; - int j; - int active = lq_sta->active_tbl; - - cnt += - sprintf(&buf[cnt], " %2dMbs: ", iwl_rates[i].ieee / 2); - - mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1)); - for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1) - buf[cnt++] = - (lq_sta->lq_info[active].win[i].data & mask) - ? '1' : '0'; - - samples += lq_sta->lq_info[active].win[i].counter; - good += lq_sta->lq_info[active].win[i].success_counter; - success += lq_sta->lq_info[active].win[i].success_counter * - iwl_rates[i].ieee; - - if (lq_sta->lq_info[active].win[i].stamp) { - int delta = - jiffies_to_msecs(now - - lq_sta->lq_info[active].win[i].stamp); - - if (delta > max_time) - max_time = delta; - - cnt += sprintf(&buf[cnt], "%5dms\n", delta); - } else - buf[cnt++] = '\n'; - - j = iwl4965_get_prev_ieee_rate(i); - if (j == i) - break; - i = j; - } - - /* - * Display the average rate of all samples taken. - * NOTE: We multiply # of samples by 2 since the IEEE measurement - * added from iwl_rates is actually 2X the rate. - */ - if (samples) - cnt += sprintf(&buf[cnt], - "\nAverage rate is %3d.%02dMbs over last %4dms\n" - "%3d%% success (%d good packets over %d tries)\n", - success / (2 * samples), (success * 5 / samples) % 10, - max_time, good * 100 / samples, good, samples); - else - cnt += sprintf(&buf[cnt], "\nAverage rate: 0Mbs\n"); - - cnt += sprintf(&buf[cnt], "\nrate scale type %d antenna %d " - "active_search %d rate index %d\n", lq_type, antenna, - lq_sta->search_better_tbl, sta->last_txrate_idx); - - rcu_read_unlock(); - return cnt; -} - -int iwl4965_rate_control_register(void) -{ - return ieee80211_rate_control_register(&rs_ops); -} - -void iwl4965_rate_control_unregister(void) -{ - ieee80211_rate_control_unregister(&rs_ops); -} - diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h deleted file mode 100644 index 9b9972885aa..00000000000 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h +++ /dev/null @@ -1,318 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * James P. Ketrenos - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#ifndef __iwl_4965_rs_h__ -#define __iwl_4965_rs_h__ - -#include "iwl-dev.h" - -struct iwl_rate_info { - u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ - u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ - u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ - u8 plcp_mimo3; /* uCode API: IWL_RATE_MIMO3_6M_PLCP, etc. */ - u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ - u8 prev_ieee; /* previous rate in IEEE speeds */ - u8 next_ieee; /* next rate in IEEE speeds */ - u8 prev_rs; /* previous rate used in rs algo */ - u8 next_rs; /* next rate used in rs algo */ - u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ - u8 next_rs_tgg; /* next rate used in TGG rs algo */ -}; - -/* - * These serve as indexes into - * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; - */ -enum { - IWL_RATE_1M_INDEX = 0, - IWL_RATE_2M_INDEX, - IWL_RATE_5M_INDEX, - IWL_RATE_11M_INDEX, - IWL_RATE_6M_INDEX, - IWL_RATE_9M_INDEX, - IWL_RATE_12M_INDEX, - IWL_RATE_18M_INDEX, - IWL_RATE_24M_INDEX, - IWL_RATE_36M_INDEX, - IWL_RATE_48M_INDEX, - IWL_RATE_54M_INDEX, - IWL_RATE_60M_INDEX, - IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/ - IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, - IWL_RATE_INVALID = IWL_RATE_COUNT, -}; - -enum { - IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX, - IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX, - IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX, - IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX, -}; - -/* #define vs. enum to keep from defaulting to 'large integer' */ -#define IWL_RATE_6M_MASK (1 << IWL_RATE_6M_INDEX) -#define IWL_RATE_9M_MASK (1 << IWL_RATE_9M_INDEX) -#define IWL_RATE_12M_MASK (1 << IWL_RATE_12M_INDEX) -#define IWL_RATE_18M_MASK (1 << IWL_RATE_18M_INDEX) -#define IWL_RATE_24M_MASK (1 << IWL_RATE_24M_INDEX) -#define IWL_RATE_36M_MASK (1 << IWL_RATE_36M_INDEX) -#define IWL_RATE_48M_MASK (1 << IWL_RATE_48M_INDEX) -#define IWL_RATE_54M_MASK (1 << IWL_RATE_54M_INDEX) -#define IWL_RATE_60M_MASK (1 << IWL_RATE_60M_INDEX) -#define IWL_RATE_1M_MASK (1 << IWL_RATE_1M_INDEX) -#define IWL_RATE_2M_MASK (1 << IWL_RATE_2M_INDEX) -#define IWL_RATE_5M_MASK (1 << IWL_RATE_5M_INDEX) -#define IWL_RATE_11M_MASK (1 << IWL_RATE_11M_INDEX) - -/* 4965 uCode API values for legacy bit rates, both OFDM and CCK */ -enum { - IWL_RATE_6M_PLCP = 13, - IWL_RATE_9M_PLCP = 15, - IWL_RATE_12M_PLCP = 5, - IWL_RATE_18M_PLCP = 7, - IWL_RATE_24M_PLCP = 9, - IWL_RATE_36M_PLCP = 11, - IWL_RATE_48M_PLCP = 1, - IWL_RATE_54M_PLCP = 3, - IWL_RATE_60M_PLCP = 3,/*FIXME:RS:should be removed*/ - IWL_RATE_1M_PLCP = 10, - IWL_RATE_2M_PLCP = 20, - IWL_RATE_5M_PLCP = 55, - IWL_RATE_11M_PLCP = 110, - /*FIXME:RS:change to IWL_RATE_LEGACY_??M_PLCP */ - /*FIXME:RS:add IWL_RATE_LEGACY_INVM_PLCP = 0,*/ -}; - -/* 4965 uCode API values for OFDM high-throughput (HT) bit rates */ -enum { - IWL_RATE_SISO_6M_PLCP = 0, - IWL_RATE_SISO_12M_PLCP = 1, - IWL_RATE_SISO_18M_PLCP = 2, - IWL_RATE_SISO_24M_PLCP = 3, - IWL_RATE_SISO_36M_PLCP = 4, - IWL_RATE_SISO_48M_PLCP = 5, - IWL_RATE_SISO_54M_PLCP = 6, - IWL_RATE_SISO_60M_PLCP = 7, - IWL_RATE_MIMO2_6M_PLCP = 0x8, - IWL_RATE_MIMO2_12M_PLCP = 0x9, - IWL_RATE_MIMO2_18M_PLCP = 0xa, - IWL_RATE_MIMO2_24M_PLCP = 0xb, - IWL_RATE_MIMO2_36M_PLCP = 0xc, - IWL_RATE_MIMO2_48M_PLCP = 0xd, - IWL_RATE_MIMO2_54M_PLCP = 0xe, - IWL_RATE_MIMO2_60M_PLCP = 0xf, - IWL_RATE_MIMO3_6M_PLCP = 0x10, - IWL_RATE_MIMO3_12M_PLCP = 0x11, - IWL_RATE_MIMO3_18M_PLCP = 0x12, - IWL_RATE_MIMO3_24M_PLCP = 0x13, - IWL_RATE_MIMO3_36M_PLCP = 0x14, - IWL_RATE_MIMO3_48M_PLCP = 0x15, - IWL_RATE_MIMO3_54M_PLCP = 0x16, - IWL_RATE_MIMO3_60M_PLCP = 0x17, - IWL_RATE_SISO_INVM_PLCP, - IWL_RATE_MIMO2_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, - IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, -}; - -/* MAC header values for bit rates */ -enum { - IWL_RATE_6M_IEEE = 12, - IWL_RATE_9M_IEEE = 18, - IWL_RATE_12M_IEEE = 24, - IWL_RATE_18M_IEEE = 36, - IWL_RATE_24M_IEEE = 48, - IWL_RATE_36M_IEEE = 72, - IWL_RATE_48M_IEEE = 96, - IWL_RATE_54M_IEEE = 108, - IWL_RATE_60M_IEEE = 120, - IWL_RATE_1M_IEEE = 2, - IWL_RATE_2M_IEEE = 4, - IWL_RATE_5M_IEEE = 11, - IWL_RATE_11M_IEEE = 22, -}; - -#define IWL_CCK_BASIC_RATES_MASK \ - (IWL_RATE_1M_MASK | \ - IWL_RATE_2M_MASK) - -#define IWL_CCK_RATES_MASK \ - (IWL_BASIC_RATES_MASK | \ - IWL_RATE_5M_MASK | \ - IWL_RATE_11M_MASK) - -#define IWL_OFDM_BASIC_RATES_MASK \ - (IWL_RATE_6M_MASK | \ - IWL_RATE_12M_MASK | \ - IWL_RATE_24M_MASK) - -#define IWL_OFDM_RATES_MASK \ - (IWL_OFDM_BASIC_RATES_MASK | \ - IWL_RATE_9M_MASK | \ - IWL_RATE_18M_MASK | \ - IWL_RATE_36M_MASK | \ - IWL_RATE_48M_MASK | \ - IWL_RATE_54M_MASK) - -#define IWL_BASIC_RATES_MASK \ - (IWL_OFDM_BASIC_RATES_MASK | \ - IWL_CCK_BASIC_RATES_MASK) - -#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) - -#define IWL_INVALID_VALUE -1 - -#define IWL_MIN_RSSI_VAL -100 -#define IWL_MAX_RSSI_VAL 0 - -/* These values specify how many Tx frame attempts before - * searching for a new modulation mode */ -#define IWL_LEGACY_FAILURE_LIMIT 160 -#define IWL_LEGACY_SUCCESS_LIMIT 480 -#define IWL_LEGACY_TABLE_COUNT 160 - -#define IWL_NONE_LEGACY_FAILURE_LIMIT 400 -#define IWL_NONE_LEGACY_SUCCESS_LIMIT 4500 -#define IWL_NONE_LEGACY_TABLE_COUNT 1500 - -/* Success ratio (ACKed / attempted tx frames) values (perfect is 128 * 100) */ -#define IWL_RS_GOOD_RATIO 12800 /* 100% */ -#define IWL_RATE_SCALE_SWITCH 10880 /* 85% */ -#define IWL_RATE_HIGH_TH 10880 /* 85% */ -#define IWL_RATE_INCREASE_TH 8960 /* 70% */ -#define IWL_RATE_DECREASE_TH 1920 /* 15% */ - -/* possible actions when in legacy mode */ -#define IWL_LEGACY_SWITCH_ANTENNA 0 -#define IWL_LEGACY_SWITCH_SISO 1 -#define IWL_LEGACY_SWITCH_MIMO2 2 - -/* possible actions when in siso mode */ -#define IWL_SISO_SWITCH_ANTENNA 0 -#define IWL_SISO_SWITCH_MIMO2 1 -#define IWL_SISO_SWITCH_GI 2 - -/* possible actions when in mimo mode */ -#define IWL_MIMO_SWITCH_ANTENNA_A 0 -#define IWL_MIMO_SWITCH_ANTENNA_B 1 -#define IWL_MIMO_SWITCH_GI 2 - -/*FIXME:RS:separate MIMO2/3 transitions*/ - -/*FIXME:RS:add posible acctions for MIMO3*/ - -#define IWL_ACTION_LIMIT 3 /* # possible actions */ - -#define LQ_SIZE 2 /* 2 mode tables: "Active" and "Search" */ - -/* load per tid defines for A-MPDU activation */ -#define IWL_AGG_TPT_THREHOLD 0 -#define IWL_AGG_LOAD_THRESHOLD 10 -#define IWL_AGG_ALL_TID 0xff -#define TID_QUEUE_CELL_SPACING 50 /*mS */ -#define TID_QUEUE_MAX_SIZE 20 -#define TID_ROUND_VALUE 5 /* mS */ -#define TID_MAX_LOAD_COUNT 8 - -#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING) -#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y)) - -extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; - -enum iwl_table_type { - LQ_NONE, - LQ_G, /* legacy types */ - LQ_A, - LQ_SISO, /* high-throughput types */ - LQ_MIMO2, - LQ_MIMO3, - LQ_MAX, -}; - -#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A)) -#define is_siso(tbl) ((tbl) == LQ_SISO) -#define is_mimo2(tbl) ((tbl) == LQ_MIMO2) -#define is_mimo3(tbl) ((tbl) == LQ_MIMO3) -#define is_mimo(tbl) (is_mimo2(tbl) || is_mimo3(tbl)) -#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl)) -#define is_a_band(tbl) ((tbl) == LQ_A) -#define is_g_and(tbl) ((tbl) == LQ_G) - -#define ANT_NONE 0x0 -#define ANT_A BIT(0) -#define ANT_B BIT(1) -#define ANT_AB (ANT_A | ANT_B) -#define ANT_C BIT(2) -#define ANT_AC (ANT_A | ANT_C) -#define ANT_BC (ANT_B | ANT_C) -#define ANT_ABC (ANT_AB | ANT_C) - -static inline u8 num_of_ant(u8 mask) -{ - return !!((mask) & ANT_A) + - !!((mask) & ANT_B) + - !!((mask) & ANT_C); -} - -static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) -{ - u8 rate = iwl_rates[rate_index].prev_ieee; - - if (rate == IWL_RATE_INVALID) - rate = rate_index; - return rate; -} - -/** - * iwl4965_fill_rs_info - Fill an output text buffer with the rate representation - * - * NOTE: This is provided as a quick mechanism for a user to visualize - * the performance of the rate control algorithm and is not meant to be - * parsed software. - */ -extern int iwl4965_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id); - -/** - * iwl4965_rate_control_register - Register the rate control algorithm callbacks - * - * Since the rate control algorithm is hardware specific, there is no need - * or reason to place it as a stand alone module. The driver can call - * iwl4965_rate_control_register in order to register the rate control callbacks - * with the mac80211 subsystem. This should be performed prior to calling - * ieee80211_register_hw - * - */ -extern int iwl4965_rate_control_register(void); - -/** - * iwl4965_rate_control_unregister - Unregister the rate control callbacks - * - * This should be called after calling ieee80211_unregister_hw, but before - * the driver is unloaded. - */ -extern void iwl4965_rate_control_unregister(void); - -#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c new file mode 100644 index 00000000000..eee22c6dec7 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -0,0 +1,2704 @@ +/****************************************************************************** + * + * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "../net/mac80211/rate.h" + +#include "iwl-dev.h" +#include "iwl-sta.h" +#include "iwl-core.h" +#include "iwl-helpers.h" + +#define RS_NAME "iwl-agn-rs" + +#define NUM_TRY_BEFORE_ANT_TOGGLE 1 +#define IWL_NUMBER_TRY 1 +#define IWL_HT_NUMBER_TRY 3 + +#define IWL_RATE_MAX_WINDOW 62 /* # tx in history window */ +#define IWL_RATE_MIN_FAILURE_TH 6 /* min failures to calc tpt */ +#define IWL_RATE_MIN_SUCCESS_TH 8 /* min successes to calc tpt */ + +/* max time to accum history 2 seconds */ +#define IWL_RATE_SCALE_FLUSH_INTVL (2*HZ) + +static u8 rs_ht_to_legacy[] = { + IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, + IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, + IWL_RATE_6M_INDEX, + IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX, + IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX, + IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX, + IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX +}; + +static const u8 ant_toggle_lookup[] = { + /*ANT_NONE -> */ ANT_NONE, + /*ANT_A -> */ ANT_B, + /*ANT_B -> */ ANT_C, + /*ANT_AB -> */ ANT_BC, + /*ANT_C -> */ ANT_A, + /*ANT_AC -> */ ANT_AB, + /*ANT_BC -> */ ANT_AC, + /*ANT_ABC -> */ ANT_ABC, +}; + +/** + * struct iwl_rate_scale_data -- tx success history for one rate + */ +struct iwl_rate_scale_data { + u64 data; /* bitmap of successful frames */ + s32 success_counter; /* number of frames successful */ + s32 success_ratio; /* per-cent * 128 */ + s32 counter; /* number of frames attempted */ + s32 average_tpt; /* success ratio * expected throughput */ + unsigned long stamp; +}; + +/** + * struct iwl_scale_tbl_info -- tx params and success history for all rates + * + * There are two of these in struct iwl_lq_sta, + * one for "active", and one for "search". + */ +struct iwl_scale_tbl_info { + enum iwl_table_type lq_type; + u8 ant_type; + u8 is_SGI; /* 1 = short guard interval */ + u8 is_fat; /* 1 = 40 MHz channel width */ + u8 is_dup; /* 1 = duplicated data streams */ + u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ + s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ + u32 current_rate; /* rate_n_flags, uCode API format */ + struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ +}; + +struct iwl_traffic_load { + unsigned long time_stamp; /* age of the oldest statistics */ + u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time + * slice */ + u32 total; /* total num of packets during the + * last TID_MAX_TIME_DIFF */ + u8 queue_count; /* number of queues that has + * been used since the last cleanup */ + u8 head; /* start of the circular buffer */ +}; + +/** + * struct iwl_lq_sta -- driver's rate scaling private structure + * + * Pointer to this gets passed back and forth between driver and mac80211. + */ +struct iwl_lq_sta { + u8 active_tbl; /* index of active table, range 0-1 */ + u8 enable_counter; /* indicates HT mode */ + u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */ + u8 search_better_tbl; /* 1: currently trying alternate mode */ + s32 last_tpt; + + /* The following determine when to search for a new mode */ + u32 table_count_limit; + u32 max_failure_limit; /* # failed frames before new search */ + u32 max_success_limit; /* # successful frames before new search */ + u32 table_count; + u32 total_failed; /* total failed frames, any/all rates */ + u32 total_success; /* total successful frames, any/all rates */ + u32 flush_timer; /* time staying in mode before new search */ + + u8 action_counter; /* # mode-switch actions tried */ + u8 is_green; + u8 is_dup; + enum ieee80211_band band; + u8 ibss_sta_added; + + /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ + u32 supp_rates; + u16 active_legacy_rate; + u16 active_siso_rate; + u16 active_mimo2_rate; + u16 active_mimo3_rate; + u16 active_rate_basic; + + struct iwl_link_quality_cmd lq; + struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ + struct iwl_traffic_load load[TID_MAX_LOAD_COUNT]; + u8 tx_agg_tid_en; +#ifdef CONFIG_MAC80211_DEBUGFS + struct dentry *rs_sta_dbgfs_scale_table_file; + struct dentry *rs_sta_dbgfs_stats_table_file; + struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; + u32 dbg_fixed_rate; +#endif + struct iwl_priv *drv; +}; + +static void rs_rate_scale_perform(struct iwl_priv *priv, + struct net_device *dev, + struct ieee80211_hdr *hdr, + struct sta_info *sta); +static void rs_fill_link_cmd(const struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, u32 rate_n_flags); + + +#ifdef CONFIG_MAC80211_DEBUGFS +static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, + u32 *rate_n_flags, int index); +#else +static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, + u32 *rate_n_flags, int index) +{} +#endif + +/* + * Expected throughput metrics for following rates: + * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits + * "G" is the only table that supports CCK (the first 4 rates). + */ +/*FIXME:RS:need to spearate tables for MIMO2/MIMO3*/ +static s32 expected_tpt_A[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186 +}; + +static s32 expected_tpt_G[IWL_RATE_COUNT] = { + 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 186 +}; + +static s32 expected_tpt_siso20MHz[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 42, 42, 76, 102, 124, 159, 183, 193, 202 +}; + +static s32 expected_tpt_siso20MHzSGI[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 46, 46, 82, 110, 132, 168, 192, 202, 211 +}; + +static s32 expected_tpt_mimo20MHz[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251 +}; + +static s32 expected_tpt_mimo20MHzSGI[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 81, 81, 131, 164, 188, 222, 243, 251, 257 +}; + +static s32 expected_tpt_siso40MHz[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 77, 77, 127, 160, 184, 220, 242, 250, 257 +}; + +static s32 expected_tpt_siso40MHzSGI[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 83, 83, 135, 169, 193, 229, 250, 257, 264 +}; + +static s32 expected_tpt_mimo40MHz[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289 +}; + +static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293 +}; + +static inline u8 rs_extract_rate(u32 rate_n_flags) +{ + return (u8)(rate_n_flags & 0xFF); +} + +static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) +{ + window->data = 0; + window->success_counter = 0; + window->success_ratio = IWL_INVALID_VALUE; + window->counter = 0; + window->average_tpt = IWL_INVALID_VALUE; + window->stamp = 0; +} + +static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type) +{ + return ((ant_type & valid_antenna) == ant_type); +} + +/* + * removes the old data from the statistics. All data that is older than + * TID_MAX_TIME_DIFF, will be deleted. + */ +static void rs_tl_rm_old_stats(struct iwl_traffic_load *tl, u32 curr_time) +{ + /* The oldest age we want to keep */ + u32 oldest_time = curr_time - TID_MAX_TIME_DIFF; + + while (tl->queue_count && + (tl->time_stamp < oldest_time)) { + tl->total -= tl->packet_count[tl->head]; + tl->packet_count[tl->head] = 0; + tl->time_stamp += TID_QUEUE_CELL_SPACING; + tl->queue_count--; + tl->head++; + if (tl->head >= TID_QUEUE_MAX_SIZE) + tl->head = 0; + } +} + +/* + * increment traffic load value for tid and also remove + * any old values if passed the certain time period + */ +static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data, + struct ieee80211_hdr *hdr) +{ + u32 curr_time = jiffies_to_msecs(jiffies); + u32 time_diff; + s32 index; + struct iwl_traffic_load *tl = NULL; + __le16 fc = hdr->frame_control; + u8 tid; + + if (ieee80211_is_data_qos(fc)) { + u8 *qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & 0xf; + } else + return MAX_TID_COUNT; + + tl = &lq_data->load[tid]; + + curr_time -= curr_time % TID_ROUND_VALUE; + + /* Happens only for the first packet. Initialize the data */ + if (!(tl->queue_count)) { + tl->total = 1; + tl->time_stamp = curr_time; + tl->queue_count = 1; + tl->head = 0; + tl->packet_count[0] = 1; + return MAX_TID_COUNT; + } + + time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time); + index = time_diff / TID_QUEUE_CELL_SPACING; + + /* The history is too long: remove data that is older than */ + /* TID_MAX_TIME_DIFF */ + if (index >= TID_QUEUE_MAX_SIZE) + rs_tl_rm_old_stats(tl, curr_time); + + index = (tl->head + index) % TID_QUEUE_MAX_SIZE; + tl->packet_count[index] = tl->packet_count[index] + 1; + tl->total = tl->total + 1; + + if ((index + 1) > tl->queue_count) + tl->queue_count = index + 1; + + return tid; +} + +/* + get the traffic load value for tid +*/ +static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid) +{ + u32 curr_time = jiffies_to_msecs(jiffies); + u32 time_diff; + s32 index; + struct iwl_traffic_load *tl = NULL; + + if (tid >= TID_MAX_LOAD_COUNT) + return 0; + + tl = &(lq_data->load[tid]); + + curr_time -= curr_time % TID_ROUND_VALUE; + + if (!(tl->queue_count)) + return 0; + + time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time); + index = time_diff / TID_QUEUE_CELL_SPACING; + + /* The history is too long: remove data that is older than */ + /* TID_MAX_TIME_DIFF */ + if (index >= TID_QUEUE_MAX_SIZE) + rs_tl_rm_old_stats(tl, curr_time); + + return tl->total; +} + +static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, + struct iwl_lq_sta *lq_data, u8 tid, + struct sta_info *sta) +{ + unsigned long state; + DECLARE_MAC_BUF(mac); + + spin_lock_bh(&sta->lock); + state = sta->ampdu_mlme.tid_state_tx[tid]; + spin_unlock_bh(&sta->lock); + + if (state == HT_AGG_STATE_IDLE && + rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { + IWL_DEBUG_HT("Starting Tx agg: STA: %s tid: %d\n", + print_mac(mac, sta->addr), tid); + ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid); + } +} + +static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid, + struct iwl_lq_sta *lq_data, + struct sta_info *sta) +{ + if ((tid < TID_MAX_LOAD_COUNT)) + rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta); + else if (tid == IWL_AGG_ALL_TID) + for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) + rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta); +} + +static inline int get_num_of_ant_from_rate(u32 rate_n_flags) +{ + return (!!(rate_n_flags & RATE_MCS_ANT_A_MSK) + + !!(rate_n_flags & RATE_MCS_ANT_B_MSK) + + !!(rate_n_flags & RATE_MCS_ANT_C_MSK)); +} + +/** + * rs_collect_tx_data - Update the success/failure sliding window + * + * We keep a sliding window of the last 62 packets transmitted + * at this rate. window->data contains the bitmask of successful + * packets. + */ +static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, + int scale_index, s32 tpt, int retries, + int successes) +{ + struct iwl_rate_scale_data *window = NULL; + static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1)); + s32 fail_count; + + if (scale_index < 0 || scale_index >= IWL_RATE_COUNT) + return -EINVAL; + + /* Select data for current tx bit rate */ + window = &(windows[scale_index]); + + /* + * Keep track of only the latest 62 tx frame attempts in this rate's + * history window; anything older isn't really relevant any more. + * If we have filled up the sliding window, drop the oldest attempt; + * if the oldest attempt (highest bit in bitmap) shows "success", + * subtract "1" from the success counter (this is the main reason + * we keep these bitmaps!). + */ + while (retries > 0) { + if (window->counter >= IWL_RATE_MAX_WINDOW) { + + /* remove earliest */ + window->counter = IWL_RATE_MAX_WINDOW - 1; + + if (window->data & mask) { + window->data &= ~mask; + window->success_counter--; + } + } + + /* Increment frames-attempted counter */ + window->counter++; + + /* Shift bitmap by one frame (throw away oldest history), + * OR in "1", and increment "success" if this + * frame was successful. */ + window->data <<= 1;; + if (successes > 0) { + window->success_counter++; + window->data |= 0x1; + successes--; + } + + retries--; + } + + /* Calculate current success ratio, avoid divide-by-0! */ + if (window->counter > 0) + window->success_ratio = 128 * (100 * window->success_counter) + / window->counter; + else + window->success_ratio = IWL_INVALID_VALUE; + + fail_count = window->counter - window->success_counter; + + /* Calculate average throughput, if we have enough history. */ + if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) || + (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH)) + window->average_tpt = (window->success_ratio * tpt + 64) / 128; + else + window->average_tpt = IWL_INVALID_VALUE; + + /* Tag this window as having been updated */ + window->stamp = jiffies; + + return 0; +} + +/* + * Fill uCode API rate_n_flags field, based on "search" or "active" table. + */ +/* FIXME:RS:remove this function and put the flags statically in the table */ +static u32 rate_n_flags_from_tbl(struct iwl_scale_tbl_info *tbl, + int index, u8 use_green) +{ + u32 rate_n_flags = 0; + + if (is_legacy(tbl->lq_type)) { + rate_n_flags = iwl_rates[index].plcp; + if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) + rate_n_flags |= RATE_MCS_CCK_MSK; + + } else if (is_Ht(tbl->lq_type)) { + if (index > IWL_LAST_OFDM_RATE) { + IWL_ERROR("invalid HT rate index %d\n", index); + index = IWL_LAST_OFDM_RATE; + } + rate_n_flags = RATE_MCS_HT_MSK; + + if (is_siso(tbl->lq_type)) + rate_n_flags |= iwl_rates[index].plcp_siso; + else if (is_mimo2(tbl->lq_type)) + rate_n_flags |= iwl_rates[index].plcp_mimo2; + else + rate_n_flags |= iwl_rates[index].plcp_mimo3; + } else { + IWL_ERROR("Invalid tbl->lq_type %d\n", tbl->lq_type); + } + + rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) & + RATE_MCS_ANT_ABC_MSK); + + if (is_Ht(tbl->lq_type)) { + if (tbl->is_fat) { + if (tbl->is_dup) + rate_n_flags |= RATE_MCS_DUP_MSK; + else + rate_n_flags |= RATE_MCS_FAT_MSK; + } + if (tbl->is_SGI) + rate_n_flags |= RATE_MCS_SGI_MSK; + + if (use_green) { + rate_n_flags |= RATE_MCS_GF_MSK; + if (is_siso(tbl->lq_type) && tbl->is_SGI) { + rate_n_flags &= ~RATE_MCS_SGI_MSK; + IWL_ERROR("GF was set with SGI:SISO\n"); + } + } + } + return rate_n_flags; +} + +/* + * Interpret uCode API's rate_n_flags format, + * fill "search" or "active" tx mode table. + */ +static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags, + enum ieee80211_band band, + struct iwl_scale_tbl_info *tbl, + int *rate_idx) +{ + u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK); + u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags); + u8 mcs; + + *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); + + if (*rate_idx == IWL_RATE_INVALID) { + *rate_idx = -1; + return -EINVAL; + } + tbl->is_SGI = 0; /* default legacy setup */ + tbl->is_fat = 0; + tbl->is_dup = 0; + tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS); + tbl->lq_type = LQ_NONE; + + /* legacy rate format */ + if (!(rate_n_flags & RATE_MCS_HT_MSK)) { + if (num_of_ant == 1) { + if (band == IEEE80211_BAND_5GHZ) + tbl->lq_type = LQ_A; + else + tbl->lq_type = LQ_G; + } + /* HT rate format */ + } else { + if (rate_n_flags & RATE_MCS_SGI_MSK) + tbl->is_SGI = 1; + + if ((rate_n_flags & RATE_MCS_FAT_MSK) || + (rate_n_flags & RATE_MCS_DUP_MSK)) + tbl->is_fat = 1; + + if (rate_n_flags & RATE_MCS_DUP_MSK) + tbl->is_dup = 1; + + mcs = rs_extract_rate(rate_n_flags); + + /* SISO */ + if (mcs <= IWL_RATE_SISO_60M_PLCP) { + if (num_of_ant == 1) + tbl->lq_type = LQ_SISO; /*else NONE*/ + /* MIMO2 */ + } else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) { + if (num_of_ant == 2) + tbl->lq_type = LQ_MIMO2; + /* MIMO3 */ + } else { + if (num_of_ant == 3) + tbl->lq_type = LQ_MIMO3; + } + } + return 0; +} + +/* switch to another antenna/antennas and return 1 */ +/* if no other valid antenna found, return 0 */ +static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, + struct iwl_scale_tbl_info *tbl) +{ + u8 new_ant_type; + + if (!tbl->ant_type || tbl->ant_type > ANT_ABC) + return 0; + + if (!rs_is_valid_ant(valid_ant, tbl->ant_type)) + return 0; + + new_ant_type = ant_toggle_lookup[tbl->ant_type]; + + while ((new_ant_type != tbl->ant_type) && + !rs_is_valid_ant(valid_ant, new_ant_type)) + new_ant_type = ant_toggle_lookup[new_ant_type]; + + if (new_ant_type == tbl->ant_type) + return 0; + + tbl->ant_type = new_ant_type; + *rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK; + *rate_n_flags |= new_ant_type << RATE_MCS_ANT_POS; + return 1; +} + +/* FIXME:RS: in 4965 we don't use greenfield at all */ +/* FIXME:RS: don't use greenfield for now in TX */ +#if 0 +static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf) +{ + return ((conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && + priv->current_ht_config.is_green_field && + !priv->current_ht_config.non_GF_STA_present); +} +#endif +static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf) +{ + return 0; +} + +/** + * rs_get_supported_rates - get the available rates + * + * if management frame or broadcast frame only return + * basic available rates. + * + */ +static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta, + struct ieee80211_hdr *hdr, + enum iwl_table_type rate_type) +{ + if (hdr && is_multicast_ether_addr(hdr->addr1) && + lq_sta->active_rate_basic) + return lq_sta->active_rate_basic; + + if (is_legacy(rate_type)) { + return lq_sta->active_legacy_rate; + } else { + if (is_siso(rate_type)) + return lq_sta->active_siso_rate; + else if (is_mimo2(rate_type)) + return lq_sta->active_mimo2_rate; + else + return lq_sta->active_mimo3_rate; + } +} + +static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask, + int rate_type) +{ + u8 high = IWL_RATE_INVALID; + u8 low = IWL_RATE_INVALID; + + /* 802.11A or ht walks to the next literal adjacent rate in + * the rate table */ + if (is_a_band(rate_type) || !is_legacy(rate_type)) { + int i; + u32 mask; + + /* Find the previous rate that is in the rate mask */ + i = index - 1; + for (mask = (1 << i); i >= 0; i--, mask >>= 1) { + if (rate_mask & mask) { + low = i; + break; + } + } + + /* Find the next rate that is in the rate mask */ + i = index + 1; + for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) { + if (rate_mask & mask) { + high = i; + break; + } + } + + return (high << 8) | low; + } + + low = index; + while (low != IWL_RATE_INVALID) { + low = iwl_rates[low].prev_rs; + if (low == IWL_RATE_INVALID) + break; + if (rate_mask & (1 << low)) + break; + IWL_DEBUG_RATE("Skipping masked lower rate: %d\n", low); + } + + high = index; + while (high != IWL_RATE_INVALID) { + high = iwl_rates[high].next_rs; + if (high == IWL_RATE_INVALID) + break; + if (rate_mask & (1 << high)) + break; + IWL_DEBUG_RATE("Skipping masked higher rate: %d\n", high); + } + + return (high << 8) | low; +} + +static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, + struct iwl_scale_tbl_info *tbl, + u8 scale_index, u8 ht_possible) +{ + s32 low; + u16 rate_mask; + u16 high_low; + u8 switch_to_legacy = 0; + u8 is_green = lq_sta->is_green; + + /* check if we need to switch from HT to legacy rates. + * assumption is that mandatory rates (1Mbps or 6Mbps) + * are always supported (spec demand) */ + if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) { + switch_to_legacy = 1; + scale_index = rs_ht_to_legacy[scale_index]; + if (lq_sta->band == IEEE80211_BAND_5GHZ) + tbl->lq_type = LQ_A; + else + tbl->lq_type = LQ_G; + + if (num_of_ant(tbl->ant_type) > 1) + tbl->ant_type = ANT_A;/*FIXME:RS*/ + + tbl->is_fat = 0; + tbl->is_SGI = 0; + } + + rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type); + + /* Mask with station rate restriction */ + if (is_legacy(tbl->lq_type)) { + /* supp_rates has no CCK bits in A mode */ + if (lq_sta->band == IEEE80211_BAND_5GHZ) + rate_mask = (u16)(rate_mask & + (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE)); + else + rate_mask = (u16)(rate_mask & lq_sta->supp_rates); + } + + /* If we switched from HT to legacy, check current rate */ + if (switch_to_legacy && (rate_mask & (1 << scale_index))) { + low = scale_index; + goto out; + } + + high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask, + tbl->lq_type); + low = high_low & 0xff; + + if (low == IWL_RATE_INVALID) + low = scale_index; + +out: + return rate_n_flags_from_tbl(tbl, low, is_green); +} + +/* + * mac80211 sends us Tx status + */ +static void rs_tx_status(void *priv_rate, struct net_device *dev, + struct sk_buff *skb) +{ + int status; + u8 retries; + int rs_index, index = 0; + struct iwl_lq_sta *lq_sta; + struct iwl_link_quality_cmd *table; + struct sta_info *sta; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hw *hw = local_to_hw(local); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct iwl_rate_scale_data *window = NULL; + struct iwl_rate_scale_data *search_win = NULL; + u32 tx_rate; + struct iwl_scale_tbl_info tbl_type; + struct iwl_scale_tbl_info *curr_tbl, *search_tbl; + u8 active_index = 0; + __le16 fc = hdr->frame_control; + s32 tpt = 0; + + IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n"); + + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) + return; + + /* This packet was aggregated but doesn't carry rate scale info */ + if ((info->flags & IEEE80211_TX_CTL_AMPDU) && + !(info->flags & IEEE80211_TX_STAT_AMPDU)) + return; + + retries = info->status.retry_count; + + if (retries > 15) + retries = 15; + + rcu_read_lock(); + + sta = sta_info_get(local, hdr->addr1); + + if (!sta || !sta->rate_ctrl_priv) + goto out; + + + lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; + + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + !lq_sta->ibss_sta_added) + goto out; + + table = &lq_sta->lq; + active_index = lq_sta->active_tbl; + + curr_tbl = &(lq_sta->lq_info[active_index]); + search_tbl = &(lq_sta->lq_info[(1 - active_index)]); + window = (struct iwl_rate_scale_data *)&(curr_tbl->win[0]); + search_win = (struct iwl_rate_scale_data *)&(search_tbl->win[0]); + + /* + * Ignore this Tx frame response if its initial rate doesn't match + * that of latest Link Quality command. There may be stragglers + * from a previous Link Quality command, but we're no longer interested + * in those; they're either from the "active" mode while we're trying + * to check "search" mode, or a prior "search" mode after we've moved + * to a new "search" mode (which might become the new "active" mode). + */ + tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags); + rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); + if (priv->band == IEEE80211_BAND_5GHZ) + rs_index -= IWL_FIRST_OFDM_RATE; + + if ((info->tx_rate_idx < 0) || + (tbl_type.is_SGI ^ + !!(info->flags & IEEE80211_TX_CTL_SHORT_GI)) || + (tbl_type.is_fat ^ + !!(info->flags & IEEE80211_TX_CTL_40_MHZ_WIDTH)) || + (tbl_type.is_dup ^ + !!(info->flags & IEEE80211_TX_CTL_DUP_DATA)) || + (tbl_type.ant_type ^ info->antenna_sel_tx) || + (!!(tx_rate & RATE_MCS_HT_MSK) ^ + !!(info->flags & IEEE80211_TX_CTL_OFDM_HT)) || + (!!(tx_rate & RATE_MCS_GF_MSK) ^ + !!(info->flags & IEEE80211_TX_CTL_GREEN_FIELD)) || + (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != + hw->wiphy->bands[info->band]->bitrates[info->tx_rate_idx].bitrate)) { + IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate); + goto out; + } + + /* Update frame history window with "failure" for each Tx retry. */ + while (retries) { + /* Look up the rate and other info used for each tx attempt. + * Each tx attempt steps one entry deeper in the rate table. */ + tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags); + rs_get_tbl_info_from_mcs(tx_rate, priv->band, + &tbl_type, &rs_index); + + /* If type matches "search" table, + * add failure to "search" history */ + if ((tbl_type.lq_type == search_tbl->lq_type) && + (tbl_type.ant_type == search_tbl->ant_type) && + (tbl_type.is_SGI == search_tbl->is_SGI)) { + if (search_tbl->expected_tpt) + tpt = search_tbl->expected_tpt[rs_index]; + else + tpt = 0; + rs_collect_tx_data(search_win, rs_index, tpt, 1, 0); + + /* Else if type matches "current/active" table, + * add failure to "current/active" history */ + } else if ((tbl_type.lq_type == curr_tbl->lq_type) && + (tbl_type.ant_type == curr_tbl->ant_type) && + (tbl_type.is_SGI == curr_tbl->is_SGI)) { + if (curr_tbl->expected_tpt) + tpt = curr_tbl->expected_tpt[rs_index]; + else + tpt = 0; + rs_collect_tx_data(window, rs_index, tpt, 1, 0); + } + + /* If not searching for a new mode, increment failed counter + * ... this helps determine when to start searching again */ + if (lq_sta->stay_in_tbl) + lq_sta->total_failed++; + --retries; + index++; + + } + + /* + * Find (by rate) the history window to update with final Tx attempt; + * if Tx was successful first try, use original rate, + * else look up the rate that was, finally, successful. + */ + tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags); + rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); + + /* Update frame history window with "success" if Tx got ACKed ... */ + status = !!(info->flags & IEEE80211_TX_STAT_ACK); + + /* If type matches "search" table, + * add final tx status to "search" history */ + if ((tbl_type.lq_type == search_tbl->lq_type) && + (tbl_type.ant_type == search_tbl->ant_type) && + (tbl_type.is_SGI == search_tbl->is_SGI)) { + if (search_tbl->expected_tpt) + tpt = search_tbl->expected_tpt[rs_index]; + else + tpt = 0; + if (info->flags & IEEE80211_TX_CTL_AMPDU) + rs_collect_tx_data(search_win, rs_index, tpt, + info->status.ampdu_ack_len, + info->status.ampdu_ack_map); + else + rs_collect_tx_data(search_win, rs_index, tpt, + 1, status); + /* Else if type matches "current/active" table, + * add final tx status to "current/active" history */ + } else if ((tbl_type.lq_type == curr_tbl->lq_type) && + (tbl_type.ant_type == curr_tbl->ant_type) && + (tbl_type.is_SGI == curr_tbl->is_SGI)) { + if (curr_tbl->expected_tpt) + tpt = curr_tbl->expected_tpt[rs_index]; + else + tpt = 0; + if (info->flags & IEEE80211_TX_CTL_AMPDU) + rs_collect_tx_data(window, rs_index, tpt, + info->status.ampdu_ack_len, + info->status.ampdu_ack_map); + else + rs_collect_tx_data(window, rs_index, tpt, + 1, status); + } + + /* If not searching for new mode, increment success/failed counter + * ... these help determine when to start searching again */ + if (lq_sta->stay_in_tbl) { + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + lq_sta->total_success += info->status.ampdu_ack_map; + lq_sta->total_failed += + (info->status.ampdu_ack_len - info->status.ampdu_ack_map); + } else { + if (status) + lq_sta->total_success++; + else + lq_sta->total_failed++; + } + } + + /* See if there's a better rate or modulation mode to try. */ + rs_rate_scale_perform(priv, dev, hdr, sta); +out: + rcu_read_unlock(); + return; +} + +/* + * Begin a period of staying with a selected modulation mode. + * Set "stay_in_tbl" flag to prevent any mode switches. + * Set frame tx success limits according to legacy vs. high-throughput, + * and reset overall (spanning all rates) tx success history statistics. + * These control how long we stay using same modulation mode before + * searching for a new mode. + */ +static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy, + struct iwl_lq_sta *lq_sta) +{ + IWL_DEBUG_RATE("we are staying in the same table\n"); + lq_sta->stay_in_tbl = 1; /* only place this gets set */ + if (is_legacy) { + lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT; + lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT; + lq_sta->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT; + } else { + lq_sta->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT; + lq_sta->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT; + lq_sta->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT; + } + lq_sta->table_count = 0; + lq_sta->total_failed = 0; + lq_sta->total_success = 0; +} + +/* + * Find correct throughput table for given mode of modulation + */ +static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, + struct iwl_scale_tbl_info *tbl) +{ + if (is_legacy(tbl->lq_type)) { + if (!is_a_band(tbl->lq_type)) + tbl->expected_tpt = expected_tpt_G; + else + tbl->expected_tpt = expected_tpt_A; + } else if (is_siso(tbl->lq_type)) { + if (tbl->is_fat && !lq_sta->is_dup) + if (tbl->is_SGI) + tbl->expected_tpt = expected_tpt_siso40MHzSGI; + else + tbl->expected_tpt = expected_tpt_siso40MHz; + else if (tbl->is_SGI) + tbl->expected_tpt = expected_tpt_siso20MHzSGI; + else + tbl->expected_tpt = expected_tpt_siso20MHz; + + } else if (is_mimo(tbl->lq_type)) { /* FIXME:need to separate mimo2/3 */ + if (tbl->is_fat && !lq_sta->is_dup) + if (tbl->is_SGI) + tbl->expected_tpt = expected_tpt_mimo40MHzSGI; + else + tbl->expected_tpt = expected_tpt_mimo40MHz; + else if (tbl->is_SGI) + tbl->expected_tpt = expected_tpt_mimo20MHzSGI; + else + tbl->expected_tpt = expected_tpt_mimo20MHz; + } else + tbl->expected_tpt = expected_tpt_G; +} + +/* + * Find starting rate for new "search" high-throughput mode of modulation. + * Goal is to find lowest expected rate (under perfect conditions) that is + * above the current measured throughput of "active" mode, to give new mode + * a fair chance to prove itself without too many challenges. + * + * This gets called when transitioning to more aggressive modulation + * (i.e. legacy to SISO or MIMO, or SISO to MIMO), as well as less aggressive + * (i.e. MIMO to SISO). When moving to MIMO, bit rate will typically need + * to decrease to match "active" throughput. When moving from MIMO to SISO, + * bit rate will typically need to increase, but not if performance was bad. + */ +static s32 rs_get_best_rate(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct iwl_scale_tbl_info *tbl, /* "search" */ + u16 rate_mask, s8 index) +{ + /* "active" values */ + struct iwl_scale_tbl_info *active_tbl = + &(lq_sta->lq_info[lq_sta->active_tbl]); + s32 active_sr = active_tbl->win[index].success_ratio; + s32 active_tpt = active_tbl->expected_tpt[index]; + + /* expected "search" throughput */ + s32 *tpt_tbl = tbl->expected_tpt; + + s32 new_rate, high, low, start_hi; + u16 high_low; + s8 rate = index; + + new_rate = high = low = start_hi = IWL_RATE_INVALID; + + for (; ;) { + high_low = rs_get_adjacent_rate(priv, rate, rate_mask, + tbl->lq_type); + + low = high_low & 0xff; + high = (high_low >> 8) & 0xff; + + /* + * Lower the "search" bit rate, to give new "search" mode + * approximately the same throughput as "active" if: + * + * 1) "Active" mode has been working modestly well (but not + * great), and expected "search" throughput (under perfect + * conditions) at candidate rate is above the actual + * measured "active" throughput (but less than expected + * "active" throughput under perfect conditions). + * OR + * 2) "Active" mode has been working perfectly or very well + * and expected "search" throughput (under perfect + * conditions) at candidate rate is above expected + * "active" throughput (under perfect conditions). + */ + if ((((100 * tpt_tbl[rate]) > lq_sta->last_tpt) && + ((active_sr > IWL_RATE_DECREASE_TH) && + (active_sr <= IWL_RATE_HIGH_TH) && + (tpt_tbl[rate] <= active_tpt))) || + ((active_sr >= IWL_RATE_SCALE_SWITCH) && + (tpt_tbl[rate] > active_tpt))) { + + /* (2nd or later pass) + * If we've already tried to raise the rate, and are + * now trying to lower it, use the higher rate. */ + if (start_hi != IWL_RATE_INVALID) { + new_rate = start_hi; + break; + } + + new_rate = rate; + + /* Loop again with lower rate */ + if (low != IWL_RATE_INVALID) + rate = low; + + /* Lower rate not available, use the original */ + else + break; + + /* Else try to raise the "search" rate to match "active" */ + } else { + /* (2nd or later pass) + * If we've already tried to lower the rate, and are + * now trying to raise it, use the lower rate. */ + if (new_rate != IWL_RATE_INVALID) + break; + + /* Loop again with higher rate */ + else if (high != IWL_RATE_INVALID) { + start_hi = high; + rate = high; + + /* Higher rate not available, use the original */ + } else { + break; + } + } + } + + return new_rate; +} + +/* + * Set up search table for MIMO + */ +static int rs_switch_to_mimo2(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct sta_info *sta, + struct iwl_scale_tbl_info *tbl, int index) +{ + u16 rate_mask; + s32 rate; + s8 is_green = lq_sta->is_green; + + if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || + !sta->ht_info.ht_supported) + return -1; + + if (priv->current_ht_config.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC) + return -1; + + /* Need both Tx chains/antennas to support MIMO */ + if (priv->hw_params.tx_chains_num < 2) + return -1; + + IWL_DEBUG_RATE("LQ: try to switch to MIMO2\n"); + + tbl->lq_type = LQ_MIMO2; + tbl->is_dup = lq_sta->is_dup; + tbl->action = 0; + rate_mask = lq_sta->active_mimo2_rate; + + if (priv->current_ht_config.supported_chan_width + == IWL_CHANNEL_WIDTH_40MHZ) + tbl->is_fat = 1; + else + tbl->is_fat = 0; + + /* FIXME: - don't toggle SGI here + if (tbl->is_fat) { + if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) + tbl->is_SGI = 1; + else + tbl->is_SGI = 0; + } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) + tbl->is_SGI = 1; + else + tbl->is_SGI = 0; + */ + + rs_set_expected_tpt_table(lq_sta, tbl); + + rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); + + IWL_DEBUG_RATE("LQ: MIMO2 best rate %d mask %X\n", rate, rate_mask); + + if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { + IWL_DEBUG_RATE("Can't switch with index %d rate mask %x\n", + rate, rate_mask); + return -1; + } + tbl->current_rate = rate_n_flags_from_tbl(tbl, rate, is_green); + + IWL_DEBUG_RATE("LQ: Switch to new mcs %X index is green %X\n", + tbl->current_rate, is_green); + return 0; +} + +/* + * Set up search table for SISO + */ +static int rs_switch_to_siso(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct sta_info *sta, + struct iwl_scale_tbl_info *tbl, int index) +{ + u16 rate_mask; + u8 is_green = lq_sta->is_green; + s32 rate; + + if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || + !sta->ht_info.ht_supported) + return -1; + + IWL_DEBUG_RATE("LQ: try to switch to SISO\n"); + + tbl->is_dup = lq_sta->is_dup; + tbl->lq_type = LQ_SISO; + tbl->action = 0; + rate_mask = lq_sta->active_siso_rate; + + if (priv->current_ht_config.supported_chan_width + == IWL_CHANNEL_WIDTH_40MHZ) + tbl->is_fat = 1; + else + tbl->is_fat = 0; + + /* FIXME: - don't toggle SGI here + if (tbl->is_fat) { + if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) + tbl->is_SGI = 1; + else + tbl->is_SGI = 0; + } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) + tbl->is_SGI = 1; + else + tbl->is_SGI = 0; + */ + + if (is_green) + tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/ + + rs_set_expected_tpt_table(lq_sta, tbl); + rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index); + + IWL_DEBUG_RATE("LQ: get best rate %d mask %X\n", rate, rate_mask); + if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { + IWL_DEBUG_RATE("can not switch with index %d rate mask %x\n", + rate, rate_mask); + return -1; + } + tbl->current_rate = rate_n_flags_from_tbl(tbl, rate, is_green); + IWL_DEBUG_RATE("LQ: Switch to new mcs %X index is green %X\n", + tbl->current_rate, is_green); + return 0; +} + +/* + * Try to switch to new modulation mode from legacy + */ +static int rs_move_legacy_other(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct sta_info *sta, + int index) +{ + struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); + struct iwl_scale_tbl_info *search_tbl = + &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); + struct iwl_rate_scale_data *window = &(tbl->win[index]); + u32 sz = (sizeof(struct iwl_scale_tbl_info) - + (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); + u8 start_action = tbl->action; + u8 valid_tx_ant = priv->hw_params.valid_tx_ant; + int ret = 0; + + for (; ;) { + switch (tbl->action) { + case IWL_LEGACY_SWITCH_ANTENNA: + IWL_DEBUG_RATE("LQ: Legacy toggle Antenna\n"); + + lq_sta->action_counter++; + + /* Don't change antenna if success has been great */ + if (window->success_ratio >= IWL_RS_GOOD_RATIO) + break; + + /* Set up search table to try other antenna */ + memcpy(search_tbl, tbl, sz); + + if (rs_toggle_antenna(valid_tx_ant, + &search_tbl->current_rate, search_tbl)) { + lq_sta->search_better_tbl = 1; + goto out; + } + break; + case IWL_LEGACY_SWITCH_SISO: + IWL_DEBUG_RATE("LQ: Legacy switch to SISO\n"); + + /* Set up search table to try SISO */ + memcpy(search_tbl, tbl, sz); + search_tbl->is_SGI = 0; + ret = rs_switch_to_siso(priv, lq_sta, conf, sta, + search_tbl, index); + if (!ret) { + lq_sta->search_better_tbl = 1; + lq_sta->action_counter = 0; + goto out; + } + + break; + case IWL_LEGACY_SWITCH_MIMO2: + IWL_DEBUG_RATE("LQ: Legacy switch to MIMO2\n"); + + /* Set up search table to try MIMO */ + memcpy(search_tbl, tbl, sz); + search_tbl->is_SGI = 0; + search_tbl->ant_type = ANT_AB;/*FIXME:RS*/ + /*FIXME:RS:need to check ant validity*/ + ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, + search_tbl, index); + if (!ret) { + lq_sta->search_better_tbl = 1; + lq_sta->action_counter = 0; + goto out; + } + break; + } + tbl->action++; + if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) + tbl->action = IWL_LEGACY_SWITCH_ANTENNA; + + if (tbl->action == start_action) + break; + + } + return 0; + + out: + tbl->action++; + if (tbl->action > IWL_LEGACY_SWITCH_MIMO2) + tbl->action = IWL_LEGACY_SWITCH_ANTENNA; + return 0; + +} + +/* + * Try to switch to new modulation mode from SISO + */ +static int rs_move_siso_to_other(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct sta_info *sta, int index) +{ + u8 is_green = lq_sta->is_green; + struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); + struct iwl_scale_tbl_info *search_tbl = + &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); + struct iwl_rate_scale_data *window = &(tbl->win[index]); + u32 sz = (sizeof(struct iwl_scale_tbl_info) - + (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); + u8 start_action = tbl->action; + u8 valid_tx_ant = priv->hw_params.valid_tx_ant; + int ret; + + for (;;) { + lq_sta->action_counter++; + switch (tbl->action) { + case IWL_SISO_SWITCH_ANTENNA: + IWL_DEBUG_RATE("LQ: SISO toggle Antenna\n"); + if (window->success_ratio >= IWL_RS_GOOD_RATIO) + break; + + memcpy(search_tbl, tbl, sz); + if (rs_toggle_antenna(valid_tx_ant, + &search_tbl->current_rate, search_tbl)) { + lq_sta->search_better_tbl = 1; + goto out; + } + break; + case IWL_SISO_SWITCH_MIMO2: + IWL_DEBUG_RATE("LQ: SISO switch to MIMO2\n"); + memcpy(search_tbl, tbl, sz); + search_tbl->is_SGI = 0; + search_tbl->ant_type = ANT_AB; /*FIXME:RS*/ + ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta, + search_tbl, index); + if (!ret) { + lq_sta->search_better_tbl = 1; + goto out; + } + break; + case IWL_SISO_SWITCH_GI: + if (!tbl->is_fat && + !(priv->current_ht_config.sgf & + HT_SHORT_GI_20MHZ)) + break; + if (tbl->is_fat && + !(priv->current_ht_config.sgf & + HT_SHORT_GI_40MHZ)) + break; + + IWL_DEBUG_RATE("LQ: SISO toggle SGI/NGI\n"); + + memcpy(search_tbl, tbl, sz); + if (is_green) { + if (!tbl->is_SGI) + break; + else + IWL_ERROR("SGI was set in GF+SISO\n"); + } + search_tbl->is_SGI = !tbl->is_SGI; + rs_set_expected_tpt_table(lq_sta, search_tbl); + if (tbl->is_SGI) { + s32 tpt = lq_sta->last_tpt / 100; + if (tpt >= search_tbl->expected_tpt[index]) + break; + } + search_tbl->current_rate = rate_n_flags_from_tbl( + search_tbl, index, is_green); + lq_sta->search_better_tbl = 1; + goto out; + } + tbl->action++; + if (tbl->action > IWL_SISO_SWITCH_GI) + tbl->action = IWL_SISO_SWITCH_ANTENNA; + + if (tbl->action == start_action) + break; + } + return 0; + + out: + tbl->action++; + if (tbl->action > IWL_SISO_SWITCH_GI) + tbl->action = IWL_SISO_SWITCH_ANTENNA; + return 0; +} + +/* + * Try to switch to new modulation mode from MIMO + */ +static int rs_move_mimo_to_other(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct sta_info *sta, int index) +{ + s8 is_green = lq_sta->is_green; + struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); + struct iwl_scale_tbl_info *search_tbl = + &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); + u32 sz = (sizeof(struct iwl_scale_tbl_info) - + (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); + u8 start_action = tbl->action; + /*u8 valid_tx_ant = priv->hw_params.valid_tx_ant;*/ + int ret; + + for (;;) { + lq_sta->action_counter++; + switch (tbl->action) { + case IWL_MIMO_SWITCH_ANTENNA_A: + case IWL_MIMO_SWITCH_ANTENNA_B: + IWL_DEBUG_RATE("LQ: MIMO2 switch to SISO\n"); + + /* Set up new search table for SISO */ + memcpy(search_tbl, tbl, sz); + + /*FIXME:RS:need to check ant validity + C*/ + if (tbl->action == IWL_MIMO_SWITCH_ANTENNA_A) + search_tbl->ant_type = ANT_A; + else + search_tbl->ant_type = ANT_B; + + ret = rs_switch_to_siso(priv, lq_sta, conf, sta, + search_tbl, index); + if (!ret) { + lq_sta->search_better_tbl = 1; + goto out; + } + break; + + case IWL_MIMO_SWITCH_GI: + if (!tbl->is_fat && + !(priv->current_ht_config.sgf & + HT_SHORT_GI_20MHZ)) + break; + if (tbl->is_fat && + !(priv->current_ht_config.sgf & + HT_SHORT_GI_40MHZ)) + break; + + IWL_DEBUG_RATE("LQ: MIMO toggle SGI/NGI\n"); + + /* Set up new search table for MIMO */ + memcpy(search_tbl, tbl, sz); + search_tbl->is_SGI = !tbl->is_SGI; + rs_set_expected_tpt_table(lq_sta, search_tbl); + /* + * If active table already uses the fastest possible + * modulation (dual stream with short guard interval), + * and it's working well, there's no need to look + * for a better type of modulation! + */ + if (tbl->is_SGI) { + s32 tpt = lq_sta->last_tpt / 100; + if (tpt >= search_tbl->expected_tpt[index]) + break; + } + search_tbl->current_rate = rate_n_flags_from_tbl( + search_tbl, index, is_green); + lq_sta->search_better_tbl = 1; + goto out; + + } + tbl->action++; + if (tbl->action > IWL_MIMO_SWITCH_GI) + tbl->action = IWL_MIMO_SWITCH_ANTENNA_A; + + if (tbl->action == start_action) + break; + } + + return 0; + out: + tbl->action++; + if (tbl->action > IWL_MIMO_SWITCH_GI) + tbl->action = IWL_MIMO_SWITCH_ANTENNA_A; + return 0; + +} + +/* + * Check whether we should continue using same modulation mode, or + * begin search for a new mode, based on: + * 1) # tx successes or failures while using this mode + * 2) # times calling this function + * 3) elapsed time in this mode (not used, for now) + */ +static void rs_stay_in_table(struct iwl_lq_sta *lq_sta) +{ + struct iwl_scale_tbl_info *tbl; + int i; + int active_tbl; + int flush_interval_passed = 0; + struct iwl_priv *priv; + + priv = lq_sta->drv; + active_tbl = lq_sta->active_tbl; + + tbl = &(lq_sta->lq_info[active_tbl]); + + /* If we've been disallowing search, see if we should now allow it */ + if (lq_sta->stay_in_tbl) { + + /* Elapsed time using current modulation mode */ + if (lq_sta->flush_timer) + flush_interval_passed = + time_after(jiffies, + (unsigned long)(lq_sta->flush_timer + + IWL_RATE_SCALE_FLUSH_INTVL)); + + /* + * Check if we should allow search for new modulation mode. + * If many frames have failed or succeeded, or we've used + * this same modulation for a long time, allow search, and + * reset history stats that keep track of whether we should + * allow a new search. Also (below) reset all bitmaps and + * stats in active history. + */ + if ((lq_sta->total_failed > lq_sta->max_failure_limit) || + (lq_sta->total_success > lq_sta->max_success_limit) || + ((!lq_sta->search_better_tbl) && (lq_sta->flush_timer) + && (flush_interval_passed))) { + IWL_DEBUG_RATE("LQ: stay is expired %d %d %d\n:", + lq_sta->total_failed, + lq_sta->total_success, + flush_interval_passed); + + /* Allow search for new mode */ + lq_sta->stay_in_tbl = 0; /* only place reset */ + lq_sta->total_failed = 0; + lq_sta->total_success = 0; + lq_sta->flush_timer = 0; + + /* + * Else if we've used this modulation mode enough repetitions + * (regardless of elapsed time or success/failure), reset + * history bitmaps and rate-specific stats for all rates in + * active table. + */ + } else { + lq_sta->table_count++; + if (lq_sta->table_count >= + lq_sta->table_count_limit) { + lq_sta->table_count = 0; + + IWL_DEBUG_RATE("LQ: stay in table clear win\n"); + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window( + &(tbl->win[i])); + } + } + + /* If transitioning to allow "search", reset all history + * bitmaps and stats in active table (this will become the new + * "search" table). */ + if (!lq_sta->stay_in_tbl) { + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window(&(tbl->win[i])); + } + } +} + +/* + * Do rate scaling and search for new modulation mode. + */ +static void rs_rate_scale_perform(struct iwl_priv *priv, + struct net_device *dev, + struct ieee80211_hdr *hdr, + struct sta_info *sta) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hw *hw = local_to_hw(local); + struct ieee80211_conf *conf = &hw->conf; + int low = IWL_RATE_INVALID; + int high = IWL_RATE_INVALID; + int index; + int i; + struct iwl_rate_scale_data *window = NULL; + int current_tpt = IWL_INVALID_VALUE; + int low_tpt = IWL_INVALID_VALUE; + int high_tpt = IWL_INVALID_VALUE; + u32 fail_count; + s8 scale_action = 0; + __le16 fc; + u16 rate_mask; + u8 update_lq = 0; + struct iwl_lq_sta *lq_sta; + struct iwl_scale_tbl_info *tbl, *tbl1; + u16 rate_scale_index_msk = 0; + u32 rate; + u8 is_green = 0; + u8 active_tbl = 0; + u8 done_search = 0; + u16 high_low; + s32 sr; + u8 tid = MAX_TID_COUNT; + + IWL_DEBUG_RATE("rate scale calculate new rate for skb\n"); + + fc = hdr->frame_control; + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) { + /* Send management frames and broadcast/multicast data using + * lowest rate. */ + /* TODO: this could probably be improved.. */ + return; + } + + if (!sta || !sta->rate_ctrl_priv) + return; + + lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; + + tid = rs_tl_add_packet(lq_sta, hdr); + + /* + * Select rate-scale / modulation-mode table to work with in + * the rest of this function: "search" if searching for better + * modulation mode, or "active" if doing rate scaling within a mode. + */ + if (!lq_sta->search_better_tbl) + active_tbl = lq_sta->active_tbl; + else + active_tbl = 1 - lq_sta->active_tbl; + + tbl = &(lq_sta->lq_info[active_tbl]); + is_green = lq_sta->is_green; + + /* current tx rate */ + index = sta->last_txrate_idx; + + IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index, + tbl->lq_type); + + /* rates available for this association, and for modulation mode */ + rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type); + + IWL_DEBUG_RATE("mask 0x%04X \n", rate_mask); + + /* mask with station rate restriction */ + if (is_legacy(tbl->lq_type)) { + if (lq_sta->band == IEEE80211_BAND_5GHZ) + /* supp_rates has no CCK bits in A mode */ + rate_scale_index_msk = (u16) (rate_mask & + (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE)); + else + rate_scale_index_msk = (u16) (rate_mask & + lq_sta->supp_rates); + + } else + rate_scale_index_msk = rate_mask; + + if (!rate_scale_index_msk) + rate_scale_index_msk = rate_mask; + + if (!((1 << index) & rate_scale_index_msk)) { + IWL_ERROR("Current Rate is not valid\n"); + return; + } + + /* Get expected throughput table and history window for current rate */ + if (!tbl->expected_tpt) { + IWL_ERROR("tbl->expected_tpt is NULL\n"); + return; + } + + window = &(tbl->win[index]); + + /* + * If there is not enough history to calculate actual average + * throughput, keep analyzing results of more tx frames, without + * changing rate or mode (bypass most of the rest of this function). + * Set up new rate table in uCode only if old rate is not supported + * in current association (use new rate found above). + */ + fail_count = window->counter - window->success_counter; + if ((fail_count < IWL_RATE_MIN_FAILURE_TH) && + (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) { + IWL_DEBUG_RATE("LQ: still below TH. succ=%d total=%d " + "for index %d\n", + window->success_counter, window->counter, index); + + /* Can't calculate this yet; not enough history */ + window->average_tpt = IWL_INVALID_VALUE; + + /* Should we stay with this modulation mode, + * or search for a new one? */ + rs_stay_in_table(lq_sta); + + goto out; + + /* Else we have enough samples; calculate estimate of + * actual average throughput */ + } else { + /*FIXME:RS remove this else if we don't get this error*/ + if (window->average_tpt != ((window->success_ratio * + tbl->expected_tpt[index] + 64) / 128)) { + IWL_ERROR("expected_tpt should have been calculated" + " by now\n"); + window->average_tpt = ((window->success_ratio * + tbl->expected_tpt[index] + 64) / 128); + } + } + + /* If we are searching for better modulation mode, check success. */ + if (lq_sta->search_better_tbl) { + + /* If good success, continue using the "search" mode; + * no need to send new link quality command, since we're + * continuing to use the setup that we've been trying. */ + if (window->average_tpt > lq_sta->last_tpt) { + + IWL_DEBUG_RATE("LQ: SWITCHING TO CURRENT TABLE " + "suc=%d cur-tpt=%d old-tpt=%d\n", + window->success_ratio, + window->average_tpt, + lq_sta->last_tpt); + + if (!is_legacy(tbl->lq_type)) + lq_sta->enable_counter = 1; + + /* Swap tables; "search" becomes "active" */ + lq_sta->active_tbl = active_tbl; + current_tpt = window->average_tpt; + + /* Else poor success; go back to mode in "active" table */ + } else { + + IWL_DEBUG_RATE("LQ: GOING BACK TO THE OLD TABLE " + "suc=%d cur-tpt=%d old-tpt=%d\n", + window->success_ratio, + window->average_tpt, + lq_sta->last_tpt); + + /* Nullify "search" table */ + tbl->lq_type = LQ_NONE; + + /* Revert to "active" table */ + active_tbl = lq_sta->active_tbl; + tbl = &(lq_sta->lq_info[active_tbl]); + + /* Revert to "active" rate and throughput info */ + index = iwl_hwrate_to_plcp_idx(tbl->current_rate); + current_tpt = lq_sta->last_tpt; + + /* Need to set up a new rate table in uCode */ + update_lq = 1; + } + + /* Either way, we've made a decision; modulation mode + * search is done, allow rate adjustment next time. */ + lq_sta->search_better_tbl = 0; + done_search = 1; /* Don't switch modes below! */ + goto lq_update; + } + + /* (Else) not in search of better modulation mode, try for better + * starting rate, while staying in this mode. */ + high_low = rs_get_adjacent_rate(priv, index, rate_scale_index_msk, + tbl->lq_type); + low = high_low & 0xff; + high = (high_low >> 8) & 0xff; + + sr = window->success_ratio; + + /* Collect measured throughputs for current and adjacent rates */ + current_tpt = window->average_tpt; + if (low != IWL_RATE_INVALID) + low_tpt = tbl->win[low].average_tpt; + if (high != IWL_RATE_INVALID) + high_tpt = tbl->win[high].average_tpt; + + scale_action = 0; + + /* Too many failures, decrease rate */ + if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) { + IWL_DEBUG_RATE("decrease rate because of low success_ratio\n"); + scale_action = -1; + + /* No throughput measured yet for adjacent rates; try increase. */ + } else if ((low_tpt == IWL_INVALID_VALUE) && + (high_tpt == IWL_INVALID_VALUE)) { + + if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH) + scale_action = 1; + else if (low != IWL_RATE_INVALID) + scale_action = -1; + } + + /* Both adjacent throughputs are measured, but neither one has better + * throughput; we're using the best rate, don't change it! */ + else if ((low_tpt != IWL_INVALID_VALUE) && + (high_tpt != IWL_INVALID_VALUE) && + (low_tpt < current_tpt) && + (high_tpt < current_tpt)) + scale_action = 0; + + /* At least one adjacent rate's throughput is measured, + * and may have better performance. */ + else { + /* Higher adjacent rate's throughput is measured */ + if (high_tpt != IWL_INVALID_VALUE) { + /* Higher rate has better throughput */ + if (high_tpt > current_tpt && + sr >= IWL_RATE_INCREASE_TH) { + scale_action = 1; + } else { + IWL_DEBUG_RATE + ("decrease rate because of high tpt\n"); + scale_action = -1; + } + + /* Lower adjacent rate's throughput is measured */ + } else if (low_tpt != IWL_INVALID_VALUE) { + /* Lower rate has better throughput */ + if (low_tpt > current_tpt) { + IWL_DEBUG_RATE + ("decrease rate because of low tpt\n"); + scale_action = -1; + } else if (sr >= IWL_RATE_INCREASE_TH) { + scale_action = 1; + } + } + } + + /* Sanity check; asked for decrease, but success rate or throughput + * has been good at old rate. Don't change it. */ + if ((scale_action == -1) && (low != IWL_RATE_INVALID) && + ((sr > IWL_RATE_HIGH_TH) || + (current_tpt > (100 * tbl->expected_tpt[low])))) + scale_action = 0; + + switch (scale_action) { + case -1: + /* Decrease starting rate, update uCode's rate table */ + if (low != IWL_RATE_INVALID) { + update_lq = 1; + index = low; + } + break; + case 1: + /* Increase starting rate, update uCode's rate table */ + if (high != IWL_RATE_INVALID) { + update_lq = 1; + index = high; + } + + break; + case 0: + /* No change */ + default: + break; + } + + IWL_DEBUG_RATE("choose rate scale index %d action %d low %d " + "high %d type %d\n", + index, scale_action, low, high, tbl->lq_type); + +lq_update: + /* Replace uCode's rate table for the destination station. */ + if (update_lq) { + rate = rate_n_flags_from_tbl(tbl, index, is_green); + rs_fill_link_cmd(priv, lq_sta, rate); + iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); + } + + /* Should we stay with this modulation mode, or search for a new one? */ + rs_stay_in_table(lq_sta); + + /* + * Search for new modulation mode if we're: + * 1) Not changing rates right now + * 2) Not just finishing up a search + * 3) Allowing a new search + */ + if (!update_lq && !done_search && !lq_sta->stay_in_tbl && window->counter) { + /* Save current throughput to compare with "search" throughput*/ + lq_sta->last_tpt = current_tpt; + + /* Select a new "search" modulation mode to try. + * If one is found, set up the new "search" table. */ + if (is_legacy(tbl->lq_type)) + rs_move_legacy_other(priv, lq_sta, conf, sta, index); + else if (is_siso(tbl->lq_type)) + rs_move_siso_to_other(priv, lq_sta, conf, sta, index); + else + rs_move_mimo_to_other(priv, lq_sta, conf, sta, index); + + /* If new "search" mode was selected, set up in uCode table */ + if (lq_sta->search_better_tbl) { + /* Access the "search" table, clear its history. */ + tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window(&(tbl->win[i])); + + /* Use new "search" start rate */ + index = iwl_hwrate_to_plcp_idx(tbl->current_rate); + + IWL_DEBUG_RATE("Switch current mcs: %X index: %d\n", + tbl->current_rate, index); + rs_fill_link_cmd(priv, lq_sta, tbl->current_rate); + iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); + } + + /* If the "active" (non-search) mode was legacy, + * and we've tried switching antennas, + * but we haven't been able to try HT modes (not available), + * stay with best antenna legacy modulation for a while + * before next round of mode comparisons. */ + tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); + if (is_legacy(tbl1->lq_type) && + (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) && + (lq_sta->action_counter >= 1)) { + lq_sta->action_counter = 0; + IWL_DEBUG_RATE("LQ: STAY in legacy table\n"); + rs_set_stay_in_table(priv, 1, lq_sta); + } + + /* If we're in an HT mode, and all 3 mode switch actions + * have been tried and compared, stay in this best modulation + * mode for a while before next round of mode comparisons. */ + if (lq_sta->enable_counter && + (lq_sta->action_counter >= IWL_ACTION_LIMIT)) { + if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && + (lq_sta->tx_agg_tid_en & (1 << tid)) && + (tid != MAX_TID_COUNT)) { + IWL_DEBUG_RATE("try to aggregate tid %d\n", tid); + rs_tl_turn_on_agg(priv, tid, lq_sta, sta); + } + lq_sta->action_counter = 0; + rs_set_stay_in_table(priv, 0, lq_sta); + } + + /* + * Else, don't search for a new modulation mode. + * Put new timestamp in stay-in-modulation-mode flush timer if: + * 1) Not changing rates right now + * 2) Not just finishing up a search + * 3) flush timer is empty + */ + } else { + if ((!update_lq) && (!done_search) && (!lq_sta->flush_timer)) + lq_sta->flush_timer = jiffies; + } + +out: + tbl->current_rate = rate_n_flags_from_tbl(tbl, index, is_green); + i = index; + sta->last_txrate_idx = i; + + /* sta->txrate_idx is an index to A mode rates which start + * at IWL_FIRST_OFDM_RATE + */ + if (lq_sta->band == IEEE80211_BAND_5GHZ) + sta->txrate_idx = i - IWL_FIRST_OFDM_RATE; + else + sta->txrate_idx = i; + + return; +} + + +static void rs_initialize_lq(struct iwl_priv *priv, + struct ieee80211_conf *conf, + struct sta_info *sta) +{ + struct iwl_lq_sta *lq_sta; + struct iwl_scale_tbl_info *tbl; + int rate_idx; + int i; + u32 rate; + u8 use_green = rs_use_green(priv, conf); + u8 active_tbl = 0; + u8 valid_tx_ant; + + if (!sta || !sta->rate_ctrl_priv) + goto out; + + lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; + i = sta->last_txrate_idx; + + if ((lq_sta->lq.sta_id == 0xff) && + (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)) + goto out; + + valid_tx_ant = priv->hw_params.valid_tx_ant; + + if (!lq_sta->search_better_tbl) + active_tbl = lq_sta->active_tbl; + else + active_tbl = 1 - lq_sta->active_tbl; + + tbl = &(lq_sta->lq_info[active_tbl]); + + if ((i < 0) || (i >= IWL_RATE_COUNT)) + i = 0; + + /* FIXME:RS: This is also wrong in 4965 */ + rate = iwl_rates[i].plcp; + rate |= RATE_MCS_ANT_B_MSK; + rate &= ~RATE_MCS_ANT_A_MSK; + + if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE) + rate |= RATE_MCS_CCK_MSK; + + tbl->ant_type = ANT_B; + rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx); + if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type)) + rs_toggle_antenna(valid_tx_ant, &rate, tbl); + + rate = rate_n_flags_from_tbl(tbl, rate_idx, use_green); + tbl->current_rate = rate; + rs_set_expected_tpt_table(lq_sta, tbl); + rs_fill_link_cmd(NULL, lq_sta, rate); + iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); + out: + return; +} + +static void rs_get_rate(void *priv_rate, struct net_device *dev, + struct ieee80211_supported_band *sband, + struct sk_buff *skb, + struct rate_selection *sel) +{ + + int i; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_conf *conf = &local->hw.conf; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct sta_info *sta; + __le16 fc; + struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + struct iwl_lq_sta *lq_sta; + + IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); + + rcu_read_lock(); + + sta = sta_info_get(local, hdr->addr1); + + /* Send management frames and broadcast/multicast data using lowest + * rate. */ + fc = hdr->frame_control; + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || + !sta || !sta->rate_ctrl_priv) { + sel->rate_idx = rate_lowest_index(local, sband, sta); + goto out; + } + + lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv; + i = sta->last_txrate_idx; + + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + !lq_sta->ibss_sta_added) { + u8 sta_id = iwl_find_station(priv, hdr->addr1); + DECLARE_MAC_BUF(mac); + + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_RATE("LQ: ADD station %s\n", + print_mac(mac, hdr->addr1)); + sta_id = iwl_add_station_flags(priv, hdr->addr1, + 0, CMD_ASYNC, NULL); + } + if ((sta_id != IWL_INVALID_STATION)) { + lq_sta->lq.sta_id = sta_id; + lq_sta->lq.rs_table[0].rate_n_flags = 0; + lq_sta->ibss_sta_added = 1; + rs_initialize_lq(priv, conf, sta); + } + } + + if ((i < 0) || (i > IWL_RATE_COUNT)) { + sel->rate_idx = rate_lowest_index(local, sband, sta); + goto out; + } + + if (sband->band == IEEE80211_BAND_5GHZ) + i -= IWL_FIRST_OFDM_RATE; + sel->rate_idx = i; +out: + rcu_read_unlock(); +} + +static void *rs_alloc_sta(void *priv_rate, gfp_t gfp) +{ + struct iwl_lq_sta *lq_sta; + struct iwl_priv *priv; + int i, j; + + priv = (struct iwl_priv *)priv_rate; + IWL_DEBUG_RATE("create station rate scale window\n"); + + lq_sta = kzalloc(sizeof(struct iwl_lq_sta), gfp); + + if (lq_sta == NULL) + return NULL; + lq_sta->lq.sta_id = 0xff; + + + for (j = 0; j < LQ_SIZE; j++) + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i])); + + return lq_sta; +} + +static void rs_rate_init(void *priv_rate, void *priv_sta, + struct ieee80211_local *local, + struct sta_info *sta) +{ + int i, j; + struct ieee80211_conf *conf = &local->hw.conf; + struct ieee80211_supported_band *sband; + struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + struct iwl_lq_sta *lq_sta = priv_sta; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + lq_sta->flush_timer = 0; + lq_sta->supp_rates = sta->supp_rates[sband->band]; + sta->txrate_idx = 3; + for (j = 0; j < LQ_SIZE; j++) + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i])); + + IWL_DEBUG_RATE("LQ: *** rate scale global init ***\n"); + /* TODO: what is a good starting rate for STA? About middle? Maybe not + * the lowest or the highest rate.. Could consider using RSSI from + * previous packets? Need to have IEEE 802.1X auth succeed immediately + * after assoc.. */ + + lq_sta->ibss_sta_added = 0; + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + u8 sta_id = iwl_find_station(priv, sta->addr); + DECLARE_MAC_BUF(mac); + + /* for IBSS the call are from tasklet */ + IWL_DEBUG_RATE("LQ: ADD station %s\n", + print_mac(mac, sta->addr)); + + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_RATE("LQ: ADD station %s\n", + print_mac(mac, sta->addr)); + sta_id = iwl_add_station_flags(priv, sta->addr, + 0, CMD_ASYNC, NULL); + } + if ((sta_id != IWL_INVALID_STATION)) { + lq_sta->lq.sta_id = sta_id; + lq_sta->lq.rs_table[0].rate_n_flags = 0; + } + /* FIXME: this is w/a remove it later */ + priv->assoc_station_added = 1; + } + + /* Find highest tx rate supported by hardware and destination station */ + for (i = 0; i < sband->n_bitrates; i++) + if (sta->supp_rates[sband->band] & BIT(i)) + sta->txrate_idx = i; + + sta->last_txrate_idx = sta->txrate_idx; + /* WTF is with this bogus comment? A doesn't have cck rates */ + /* For MODE_IEEE80211A, cck rates are at end of rate table */ + if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) + sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; + + lq_sta->is_dup = 0; + lq_sta->is_green = rs_use_green(priv, conf); + lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000); + lq_sta->active_rate_basic = priv->active_rate_basic; + lq_sta->band = priv->band; + /* + * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), + * supp_rates[] does not; shift to convert format, force 9 MBits off. + */ + lq_sta->active_siso_rate = conf->ht_conf.supp_mcs_set[0] << 1; + lq_sta->active_siso_rate |= conf->ht_conf.supp_mcs_set[0] & 0x1; + lq_sta->active_siso_rate &= ~((u16)0x2); + lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; + + /* Same here */ + lq_sta->active_mimo2_rate = conf->ht_conf.supp_mcs_set[1] << 1; + lq_sta->active_mimo2_rate |= conf->ht_conf.supp_mcs_set[1] & 0x1; + lq_sta->active_mimo2_rate &= ~((u16)0x2); + lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; + + lq_sta->active_mimo3_rate = conf->ht_conf.supp_mcs_set[2] << 1; + lq_sta->active_mimo3_rate |= conf->ht_conf.supp_mcs_set[2] & 0x1; + lq_sta->active_mimo3_rate &= ~((u16)0x2); + lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; + + IWL_DEBUG_RATE("SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n", + lq_sta->active_siso_rate, + lq_sta->active_mimo2_rate, + lq_sta->active_mimo3_rate); + + /* These values will be overriden later */ + lq_sta->lq.general_params.single_stream_ant_msk = ANT_A; + lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB; + + /* as default allow aggregation for all tids */ + lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; + lq_sta->drv = priv; + + rs_initialize_lq(priv, conf, sta); +} + +static void rs_fill_link_cmd(const struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, u32 new_rate) +{ + struct iwl_scale_tbl_info tbl_type; + int index = 0; + int rate_idx; + int repeat_rate = 0; + u8 ant_toggle_cnt = 0; + u8 use_ht_possible = 1; + u8 valid_tx_ant = 0; + struct iwl_link_quality_cmd *lq_cmd = &lq_sta->lq; + + /* Override starting rate (index 0) if needed for debug purposes */ + rs_dbgfs_set_mcs(lq_sta, &new_rate, index); + + /* Interpret new_rate (rate_n_flags) */ + memset(&tbl_type, 0, sizeof(tbl_type)); + rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, + &tbl_type, &rate_idx); + + /* How many times should we repeat the initial rate? */ + if (is_legacy(tbl_type.lq_type)) { + ant_toggle_cnt = 1; + repeat_rate = IWL_NUMBER_TRY; + } else { + repeat_rate = IWL_HT_NUMBER_TRY; + } + + lq_cmd->general_params.mimo_delimiter = + is_mimo(tbl_type.lq_type) ? 1 : 0; + + /* Fill 1st table entry (index 0) */ + lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate); + + if (num_of_ant(tbl_type.ant_type) == 1) { + lq_cmd->general_params.single_stream_ant_msk = + tbl_type.ant_type; + } else if (num_of_ant(tbl_type.ant_type) == 2) { + lq_cmd->general_params.dual_stream_ant_msk = + tbl_type.ant_type; + } /* otherwise we don't modify the existing value */ + + index++; + repeat_rate--; + + if (priv) + valid_tx_ant = priv->hw_params.valid_tx_ant; + + /* Fill rest of rate table */ + while (index < LINK_QUAL_MAX_RETRY_NUM) { + /* Repeat initial/next rate. + * For legacy IWL_NUMBER_TRY == 1, this loop will not execute. + * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */ + while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) { + if (is_legacy(tbl_type.lq_type)) { + if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) + ant_toggle_cnt++; + else if (priv && + rs_toggle_antenna(valid_tx_ant, + &new_rate, &tbl_type)) + ant_toggle_cnt = 1; +} + + /* Override next rate if needed for debug purposes */ + rs_dbgfs_set_mcs(lq_sta, &new_rate, index); + + /* Fill next table entry */ + lq_cmd->rs_table[index].rate_n_flags = + cpu_to_le32(new_rate); + repeat_rate--; + index++; + } + + rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type, + &rate_idx); + + /* Indicate to uCode which entries might be MIMO. + * If initial rate was MIMO, this will finally end up + * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */ + if (is_mimo(tbl_type.lq_type)) + lq_cmd->general_params.mimo_delimiter = index; + + /* Get next rate */ + new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx, + use_ht_possible); + + /* How many times should we repeat the next rate? */ + if (is_legacy(tbl_type.lq_type)) { + if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) + ant_toggle_cnt++; + else if (priv && + rs_toggle_antenna(valid_tx_ant, + &new_rate, &tbl_type)) + ant_toggle_cnt = 1; + + repeat_rate = IWL_NUMBER_TRY; + } else { + repeat_rate = IWL_HT_NUMBER_TRY; + } + + /* Don't allow HT rates after next pass. + * rs_get_lower_rate() will change type to LQ_A or LQ_G. */ + use_ht_possible = 0; + + /* Override next rate if needed for debug purposes */ + rs_dbgfs_set_mcs(lq_sta, &new_rate, index); + + /* Fill next table entry */ + lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate); + + index++; + repeat_rate--; + } + + lq_cmd->agg_params.agg_frame_cnt_limit = 64; + lq_cmd->agg_params.agg_dis_start_th = 3; + lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000); +} + +static void *rs_alloc(struct ieee80211_local *local) +{ + return local->hw.priv; +} +/* rate scale requires free function to be implemented */ +static void rs_free(void *priv_rate) +{ + return; +} + +static void rs_clear(void *priv_rate) +{ + struct iwl_priv *priv = (struct iwl_priv *) priv_rate; + + IWL_DEBUG_RATE("enter\n"); + + /* TODO - add rate scale state reset */ + + IWL_DEBUG_RATE("leave\n"); +} + +static void rs_free_sta(void *priv_rate, void *priv_sta) +{ + struct iwl_lq_sta *lq_sta = priv_sta; + struct iwl_priv *priv; + + priv = (struct iwl_priv *)priv_rate; + IWL_DEBUG_RATE("enter\n"); + kfree(lq_sta); + IWL_DEBUG_RATE("leave\n"); +} + + +#ifdef CONFIG_MAC80211_DEBUGFS +static int open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} +static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, + u32 *rate_n_flags, int index) +{ + struct iwl_priv *priv; + + priv = lq_sta->drv; + if (lq_sta->dbg_fixed_rate) { + if (index < 12) { + *rate_n_flags = lq_sta->dbg_fixed_rate; + } else { + if (lq_sta->band == IEEE80211_BAND_5GHZ) + *rate_n_flags = 0x800D; + else + *rate_n_flags = 0x820A; + } + IWL_DEBUG_RATE("Fixed rate ON\n"); + } else { + IWL_DEBUG_RATE("Fixed rate OFF\n"); + } +} + +static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct iwl_lq_sta *lq_sta = file->private_data; + struct iwl_priv *priv; + char buf[64]; + int buf_size; + u32 parsed_rate; + + priv = lq_sta->drv; + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + if (sscanf(buf, "%x", &parsed_rate) == 1) + lq_sta->dbg_fixed_rate = parsed_rate; + else + lq_sta->dbg_fixed_rate = 0; + + lq_sta->active_legacy_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */ + lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ + lq_sta->active_mimo2_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ + lq_sta->active_mimo3_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ + + IWL_DEBUG_RATE("sta_id %d rate 0x%X\n", + lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate); + + if (lq_sta->dbg_fixed_rate) { + rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate); + iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC); + } + + return count; +} + +static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + char buff[1024]; + int desc = 0; + int i = 0; + + struct iwl_lq_sta *lq_sta = file->private_data; + + desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id); + desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n", + lq_sta->total_failed, lq_sta->total_success, + lq_sta->active_legacy_rate); + desc += sprintf(buff+desc, "fixed rate 0x%X\n", + lq_sta->dbg_fixed_rate); + desc += sprintf(buff+desc, "general:" + "flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n", + lq_sta->lq.general_params.flags, + lq_sta->lq.general_params.mimo_delimiter, + lq_sta->lq.general_params.single_stream_ant_msk, + lq_sta->lq.general_params.dual_stream_ant_msk); + + desc += sprintf(buff+desc, "agg:" + "time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n", + le16_to_cpu(lq_sta->lq.agg_params.agg_time_limit), + lq_sta->lq.agg_params.agg_dis_start_th, + lq_sta->lq.agg_params.agg_frame_cnt_limit); + + desc += sprintf(buff+desc, + "Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n", + lq_sta->lq.general_params.start_rate_index[0], + lq_sta->lq.general_params.start_rate_index[1], + lq_sta->lq.general_params.start_rate_index[2], + lq_sta->lq.general_params.start_rate_index[3]); + + + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) + desc += sprintf(buff+desc, " rate[%d] 0x%X\n", + i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags)); + + return simple_read_from_buffer(user_buf, count, ppos, buff, desc); +} + +static const struct file_operations rs_sta_dbgfs_scale_table_ops = { + .write = rs_sta_dbgfs_scale_table_write, + .read = rs_sta_dbgfs_scale_table_read, + .open = open_file_generic, +}; +static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + char buff[1024]; + int desc = 0; + int i, j; + + struct iwl_lq_sta *lq_sta = file->private_data; + for (i = 0; i < LQ_SIZE; i++) { + desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n" + "rate=0x%X\n", + lq_sta->active_tbl == i?"*":"x", + lq_sta->lq_info[i].lq_type, + lq_sta->lq_info[i].is_SGI, + lq_sta->lq_info[i].is_fat, + lq_sta->lq_info[i].is_dup, + lq_sta->lq_info[i].current_rate); + for (j = 0; j < IWL_RATE_COUNT; j++) { + desc += sprintf(buff+desc, + "counter=%d success=%d %%=%d\n", + lq_sta->lq_info[i].win[j].counter, + lq_sta->lq_info[i].win[j].success_counter, + lq_sta->lq_info[i].win[j].success_ratio); + } + } + return simple_read_from_buffer(user_buf, count, ppos, buff, desc); +} + +static const struct file_operations rs_sta_dbgfs_stats_table_ops = { + .read = rs_sta_dbgfs_stats_table_read, + .open = open_file_generic, +}; + +static void rs_add_debugfs(void *priv, void *priv_sta, + struct dentry *dir) +{ + struct iwl_lq_sta *lq_sta = priv_sta; + lq_sta->rs_sta_dbgfs_scale_table_file = + debugfs_create_file("rate_scale_table", 0600, dir, + lq_sta, &rs_sta_dbgfs_scale_table_ops); + lq_sta->rs_sta_dbgfs_stats_table_file = + debugfs_create_file("rate_stats_table", 0600, dir, + lq_sta, &rs_sta_dbgfs_stats_table_ops); + lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file = + debugfs_create_u8("tx_agg_tid_enable", 0600, dir, + &lq_sta->tx_agg_tid_en); + +} + +static void rs_remove_debugfs(void *priv, void *priv_sta) +{ + struct iwl_lq_sta *lq_sta = priv_sta; + debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file); + debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file); + debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file); +} +#endif + +static struct rate_control_ops rs_ops = { + .module = NULL, + .name = RS_NAME, + .tx_status = rs_tx_status, + .get_rate = rs_get_rate, + .rate_init = rs_rate_init, + .clear = rs_clear, + .alloc = rs_alloc, + .free = rs_free, + .alloc_sta = rs_alloc_sta, + .free_sta = rs_free_sta, +#ifdef CONFIG_MAC80211_DEBUGFS + .add_sta_debugfs = rs_add_debugfs, + .remove_sta_debugfs = rs_remove_debugfs, +#endif +}; + +int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct iwl_priv *priv = hw->priv; + struct iwl_lq_sta *lq_sta; + struct sta_info *sta; + int cnt = 0, i; + u32 samples = 0, success = 0, good = 0; + unsigned long now = jiffies; + u32 max_time = 0; + u8 lq_type, antenna; + + rcu_read_lock(); + + sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); + if (!sta || !sta->rate_ctrl_priv) { + if (sta) + IWL_DEBUG_RATE("leave - no private rate data!\n"); + else + IWL_DEBUG_RATE("leave - no station!\n"); + rcu_read_unlock(); + return sprintf(buf, "station %d not found\n", sta_id); + } + + lq_sta = (void *)sta->rate_ctrl_priv; + + lq_type = lq_sta->lq_info[lq_sta->active_tbl].lq_type; + antenna = lq_sta->lq_info[lq_sta->active_tbl].ant_type; + + if (is_legacy(lq_type)) + i = IWL_RATE_54M_INDEX; + else + i = IWL_RATE_60M_INDEX; + while (1) { + u64 mask; + int j; + int active = lq_sta->active_tbl; + + cnt += + sprintf(&buf[cnt], " %2dMbs: ", iwl_rates[i].ieee / 2); + + mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1)); + for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1) + buf[cnt++] = + (lq_sta->lq_info[active].win[i].data & mask) + ? '1' : '0'; + + samples += lq_sta->lq_info[active].win[i].counter; + good += lq_sta->lq_info[active].win[i].success_counter; + success += lq_sta->lq_info[active].win[i].success_counter * + iwl_rates[i].ieee; + + if (lq_sta->lq_info[active].win[i].stamp) { + int delta = + jiffies_to_msecs(now - + lq_sta->lq_info[active].win[i].stamp); + + if (delta > max_time) + max_time = delta; + + cnt += sprintf(&buf[cnt], "%5dms\n", delta); + } else + buf[cnt++] = '\n'; + + j = iwl4965_get_prev_ieee_rate(i); + if (j == i) + break; + i = j; + } + + /* + * Display the average rate of all samples taken. + * NOTE: We multiply # of samples by 2 since the IEEE measurement + * added from iwl_rates is actually 2X the rate. + */ + if (samples) + cnt += sprintf(&buf[cnt], + "\nAverage rate is %3d.%02dMbs over last %4dms\n" + "%3d%% success (%d good packets over %d tries)\n", + success / (2 * samples), (success * 5 / samples) % 10, + max_time, good * 100 / samples, good, samples); + else + cnt += sprintf(&buf[cnt], "\nAverage rate: 0Mbs\n"); + + cnt += sprintf(&buf[cnt], "\nrate scale type %d antenna %d " + "active_search %d rate index %d\n", lq_type, antenna, + lq_sta->search_better_tbl, sta->last_txrate_idx); + + rcu_read_unlock(); + return cnt; +} + +int iwlagn_rate_control_register(void) +{ + return ieee80211_rate_control_register(&rs_ops); +} + +void iwlagn_rate_control_unregister(void) +{ + ieee80211_rate_control_unregister(&rs_ops); +} + diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h new file mode 100644 index 00000000000..3b06c9da77e --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -0,0 +1,318 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_agn_rs_h__ +#define __iwl_agn_rs_h__ + +#include "iwl-dev.h" + +struct iwl_rate_info { + u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ + u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ + u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ + u8 plcp_mimo3; /* uCode API: IWL_RATE_MIMO3_6M_PLCP, etc. */ + u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ + u8 prev_ieee; /* previous rate in IEEE speeds */ + u8 next_ieee; /* next rate in IEEE speeds */ + u8 prev_rs; /* previous rate used in rs algo */ + u8 next_rs; /* next rate used in rs algo */ + u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ + u8 next_rs_tgg; /* next rate used in TGG rs algo */ +}; + +/* + * These serve as indexes into + * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; + */ +enum { + IWL_RATE_1M_INDEX = 0, + IWL_RATE_2M_INDEX, + IWL_RATE_5M_INDEX, + IWL_RATE_11M_INDEX, + IWL_RATE_6M_INDEX, + IWL_RATE_9M_INDEX, + IWL_RATE_12M_INDEX, + IWL_RATE_18M_INDEX, + IWL_RATE_24M_INDEX, + IWL_RATE_36M_INDEX, + IWL_RATE_48M_INDEX, + IWL_RATE_54M_INDEX, + IWL_RATE_60M_INDEX, + IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/ + IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, + IWL_RATE_INVALID = IWL_RATE_COUNT, +}; + +enum { + IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX, + IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX, + IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX, + IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX, +}; + +/* #define vs. enum to keep from defaulting to 'large integer' */ +#define IWL_RATE_6M_MASK (1 << IWL_RATE_6M_INDEX) +#define IWL_RATE_9M_MASK (1 << IWL_RATE_9M_INDEX) +#define IWL_RATE_12M_MASK (1 << IWL_RATE_12M_INDEX) +#define IWL_RATE_18M_MASK (1 << IWL_RATE_18M_INDEX) +#define IWL_RATE_24M_MASK (1 << IWL_RATE_24M_INDEX) +#define IWL_RATE_36M_MASK (1 << IWL_RATE_36M_INDEX) +#define IWL_RATE_48M_MASK (1 << IWL_RATE_48M_INDEX) +#define IWL_RATE_54M_MASK (1 << IWL_RATE_54M_INDEX) +#define IWL_RATE_60M_MASK (1 << IWL_RATE_60M_INDEX) +#define IWL_RATE_1M_MASK (1 << IWL_RATE_1M_INDEX) +#define IWL_RATE_2M_MASK (1 << IWL_RATE_2M_INDEX) +#define IWL_RATE_5M_MASK (1 << IWL_RATE_5M_INDEX) +#define IWL_RATE_11M_MASK (1 << IWL_RATE_11M_INDEX) + +/* uCode API values for legacy bit rates, both OFDM and CCK */ +enum { + IWL_RATE_6M_PLCP = 13, + IWL_RATE_9M_PLCP = 15, + IWL_RATE_12M_PLCP = 5, + IWL_RATE_18M_PLCP = 7, + IWL_RATE_24M_PLCP = 9, + IWL_RATE_36M_PLCP = 11, + IWL_RATE_48M_PLCP = 1, + IWL_RATE_54M_PLCP = 3, + IWL_RATE_60M_PLCP = 3,/*FIXME:RS:should be removed*/ + IWL_RATE_1M_PLCP = 10, + IWL_RATE_2M_PLCP = 20, + IWL_RATE_5M_PLCP = 55, + IWL_RATE_11M_PLCP = 110, + /*FIXME:RS:change to IWL_RATE_LEGACY_??M_PLCP */ + /*FIXME:RS:add IWL_RATE_LEGACY_INVM_PLCP = 0,*/ +}; + +/* uCode API values for OFDM high-throughput (HT) bit rates */ +enum { + IWL_RATE_SISO_6M_PLCP = 0, + IWL_RATE_SISO_12M_PLCP = 1, + IWL_RATE_SISO_18M_PLCP = 2, + IWL_RATE_SISO_24M_PLCP = 3, + IWL_RATE_SISO_36M_PLCP = 4, + IWL_RATE_SISO_48M_PLCP = 5, + IWL_RATE_SISO_54M_PLCP = 6, + IWL_RATE_SISO_60M_PLCP = 7, + IWL_RATE_MIMO2_6M_PLCP = 0x8, + IWL_RATE_MIMO2_12M_PLCP = 0x9, + IWL_RATE_MIMO2_18M_PLCP = 0xa, + IWL_RATE_MIMO2_24M_PLCP = 0xb, + IWL_RATE_MIMO2_36M_PLCP = 0xc, + IWL_RATE_MIMO2_48M_PLCP = 0xd, + IWL_RATE_MIMO2_54M_PLCP = 0xe, + IWL_RATE_MIMO2_60M_PLCP = 0xf, + IWL_RATE_MIMO3_6M_PLCP = 0x10, + IWL_RATE_MIMO3_12M_PLCP = 0x11, + IWL_RATE_MIMO3_18M_PLCP = 0x12, + IWL_RATE_MIMO3_24M_PLCP = 0x13, + IWL_RATE_MIMO3_36M_PLCP = 0x14, + IWL_RATE_MIMO3_48M_PLCP = 0x15, + IWL_RATE_MIMO3_54M_PLCP = 0x16, + IWL_RATE_MIMO3_60M_PLCP = 0x17, + IWL_RATE_SISO_INVM_PLCP, + IWL_RATE_MIMO2_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, + IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, +}; + +/* MAC header values for bit rates */ +enum { + IWL_RATE_6M_IEEE = 12, + IWL_RATE_9M_IEEE = 18, + IWL_RATE_12M_IEEE = 24, + IWL_RATE_18M_IEEE = 36, + IWL_RATE_24M_IEEE = 48, + IWL_RATE_36M_IEEE = 72, + IWL_RATE_48M_IEEE = 96, + IWL_RATE_54M_IEEE = 108, + IWL_RATE_60M_IEEE = 120, + IWL_RATE_1M_IEEE = 2, + IWL_RATE_2M_IEEE = 4, + IWL_RATE_5M_IEEE = 11, + IWL_RATE_11M_IEEE = 22, +}; + +#define IWL_CCK_BASIC_RATES_MASK \ + (IWL_RATE_1M_MASK | \ + IWL_RATE_2M_MASK) + +#define IWL_CCK_RATES_MASK \ + (IWL_BASIC_RATES_MASK | \ + IWL_RATE_5M_MASK | \ + IWL_RATE_11M_MASK) + +#define IWL_OFDM_BASIC_RATES_MASK \ + (IWL_RATE_6M_MASK | \ + IWL_RATE_12M_MASK | \ + IWL_RATE_24M_MASK) + +#define IWL_OFDM_RATES_MASK \ + (IWL_OFDM_BASIC_RATES_MASK | \ + IWL_RATE_9M_MASK | \ + IWL_RATE_18M_MASK | \ + IWL_RATE_36M_MASK | \ + IWL_RATE_48M_MASK | \ + IWL_RATE_54M_MASK) + +#define IWL_BASIC_RATES_MASK \ + (IWL_OFDM_BASIC_RATES_MASK | \ + IWL_CCK_BASIC_RATES_MASK) + +#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) + +#define IWL_INVALID_VALUE -1 + +#define IWL_MIN_RSSI_VAL -100 +#define IWL_MAX_RSSI_VAL 0 + +/* These values specify how many Tx frame attempts before + * searching for a new modulation mode */ +#define IWL_LEGACY_FAILURE_LIMIT 160 +#define IWL_LEGACY_SUCCESS_LIMIT 480 +#define IWL_LEGACY_TABLE_COUNT 160 + +#define IWL_NONE_LEGACY_FAILURE_LIMIT 400 +#define IWL_NONE_LEGACY_SUCCESS_LIMIT 4500 +#define IWL_NONE_LEGACY_TABLE_COUNT 1500 + +/* Success ratio (ACKed / attempted tx frames) values (perfect is 128 * 100) */ +#define IWL_RS_GOOD_RATIO 12800 /* 100% */ +#define IWL_RATE_SCALE_SWITCH 10880 /* 85% */ +#define IWL_RATE_HIGH_TH 10880 /* 85% */ +#define IWL_RATE_INCREASE_TH 8960 /* 70% */ +#define IWL_RATE_DECREASE_TH 1920 /* 15% */ + +/* possible actions when in legacy mode */ +#define IWL_LEGACY_SWITCH_ANTENNA 0 +#define IWL_LEGACY_SWITCH_SISO 1 +#define IWL_LEGACY_SWITCH_MIMO2 2 + +/* possible actions when in siso mode */ +#define IWL_SISO_SWITCH_ANTENNA 0 +#define IWL_SISO_SWITCH_MIMO2 1 +#define IWL_SISO_SWITCH_GI 2 + +/* possible actions when in mimo mode */ +#define IWL_MIMO_SWITCH_ANTENNA_A 0 +#define IWL_MIMO_SWITCH_ANTENNA_B 1 +#define IWL_MIMO_SWITCH_GI 2 + +/*FIXME:RS:separate MIMO2/3 transitions*/ + +/*FIXME:RS:add posible acctions for MIMO3*/ + +#define IWL_ACTION_LIMIT 3 /* # possible actions */ + +#define LQ_SIZE 2 /* 2 mode tables: "Active" and "Search" */ + +/* load per tid defines for A-MPDU activation */ +#define IWL_AGG_TPT_THREHOLD 0 +#define IWL_AGG_LOAD_THRESHOLD 10 +#define IWL_AGG_ALL_TID 0xff +#define TID_QUEUE_CELL_SPACING 50 /*mS */ +#define TID_QUEUE_MAX_SIZE 20 +#define TID_ROUND_VALUE 5 /* mS */ +#define TID_MAX_LOAD_COUNT 8 + +#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING) +#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y)) + +extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; + +enum iwl_table_type { + LQ_NONE, + LQ_G, /* legacy types */ + LQ_A, + LQ_SISO, /* high-throughput types */ + LQ_MIMO2, + LQ_MIMO3, + LQ_MAX, +}; + +#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A)) +#define is_siso(tbl) ((tbl) == LQ_SISO) +#define is_mimo2(tbl) ((tbl) == LQ_MIMO2) +#define is_mimo3(tbl) ((tbl) == LQ_MIMO3) +#define is_mimo(tbl) (is_mimo2(tbl) || is_mimo3(tbl)) +#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl)) +#define is_a_band(tbl) ((tbl) == LQ_A) +#define is_g_and(tbl) ((tbl) == LQ_G) + +#define ANT_NONE 0x0 +#define ANT_A BIT(0) +#define ANT_B BIT(1) +#define ANT_AB (ANT_A | ANT_B) +#define ANT_C BIT(2) +#define ANT_AC (ANT_A | ANT_C) +#define ANT_BC (ANT_B | ANT_C) +#define ANT_ABC (ANT_AB | ANT_C) + +static inline u8 num_of_ant(u8 mask) +{ + return !!((mask) & ANT_A) + + !!((mask) & ANT_B) + + !!((mask) & ANT_C); +} + +static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) +{ + u8 rate = iwl_rates[rate_index].prev_ieee; + + if (rate == IWL_RATE_INVALID) + rate = rate_index; + return rate; +} + +/** + * iwl4965_fill_rs_info - Fill an output text buffer with the rate representation + * + * NOTE: This is provided as a quick mechanism for a user to visualize + * the performance of the rate control algorithm and is not meant to be + * parsed software. + */ +extern int iwl4965_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id); + +/** + * iwl4965_rate_control_register - Register the rate control algorithm callbacks + * + * Since the rate control algorithm is hardware specific, there is no need + * or reason to place it as a stand alone module. The driver can call + * iwl4965_rate_control_register in order to register the rate control callbacks + * with the mac80211 subsystem. This should be performed prior to calling + * ieee80211_register_hw + * + */ +extern int iwlagn_rate_control_register(void); + +/** + * iwl4965_rate_control_unregister - Unregister the rate control callbacks + * + * This should be called after calling ieee80211_unregister_hw, but before + * the driver is unloaded. + */ +extern void iwlagn_rate_control_unregister(void); + +#endif /* __iwl_agn__rs__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index e3427c205cc..60d443e77c3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -815,7 +815,7 @@ int iwl_setup_mac(struct iwl_priv *priv) { int ret; struct ieee80211_hw *hw = priv->hw; - hw->rate_control_algorithm = "iwl-4965-rs"; + hw->rate_control_algorithm = "iwl-agn-rs"; /* Tell mac80211 our characteristics */ hw->flags = IEEE80211_HW_SIGNAL_DBM | diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index ff16cca2b8c..7ac56b1350b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -45,6 +45,7 @@ #include "iwl-debug.h" #include "iwl-led.h" #include "iwl-power.h" +#include "iwl-agn-rs.h" /* configuration for the iwl4965 */ extern struct iwl_cfg iwl4965_agn_cfg; @@ -191,7 +192,6 @@ struct iwl4965_clip_group { const s8 clip_powers[IWL_MAX_RATES]; }; -#include "iwl-4965-rs.h" #define IWL_TX_FIFO_AC0 0 #define IWL_TX_FIFO_AC1 1 diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 6d1467d0bd9..10af82170f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -839,7 +839,7 @@ EXPORT_SYMBOL(iwl_send_lq_cmd); * for automatic fallback during transmission. * * NOTE: This sets up a default set of values. These will be replaced later - * if the driver's iwl-4965-rs rate scaling algorithm is used, instead of + * if the driver's iwl-agn-rs rate scaling algorithm is used, instead of * rc80211_simple. * * NOTE: Run REPLY_ADD_STA command to set up station table entry, before diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index ac02342d228..dcd11e9bd86 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -4503,7 +4503,7 @@ static int __init iwl4965_init(void) printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); - ret = iwl4965_rate_control_register(); + ret = iwlagn_rate_control_register(); if (ret) { IWL_ERROR("Unable to register rate control algorithm: %d\n", ret); return ret; @@ -4518,14 +4518,14 @@ static int __init iwl4965_init(void) return ret; error_register: - iwl4965_rate_control_unregister(); + iwlagn_rate_control_unregister(); return ret; } static void __exit iwl4965_exit(void) { pci_unregister_driver(&iwl_driver); - iwl4965_rate_control_unregister(); + iwlagn_rate_control_unregister(); } module_exit(iwl4965_exit); -- cgit v1.2.3 From 3ce84b9f2f495f59c4a4e68d814c348eaa497f65 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 18 Jul 2008 13:53:06 +0800 Subject: iwlwifi: kill iwl4965_fill_rs_info iwl4965_fill_rs_info was used in sysfs. This info is already present in iwl-agn-rs debugfs. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 92 ----------------------------- drivers/net/wireless/iwlwifi/iwl-agn-rs.h | 9 --- drivers/net/wireless/iwlwifi/iwl4965-base.c | 10 ---- 3 files changed, 111 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index eee22c6dec7..0e8100e7062 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2600,98 +2600,6 @@ static struct rate_control_ops rs_ops = { #endif }; -int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct iwl_priv *priv = hw->priv; - struct iwl_lq_sta *lq_sta; - struct sta_info *sta; - int cnt = 0, i; - u32 samples = 0, success = 0, good = 0; - unsigned long now = jiffies; - u32 max_time = 0; - u8 lq_type, antenna; - - rcu_read_lock(); - - sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); - if (!sta || !sta->rate_ctrl_priv) { - if (sta) - IWL_DEBUG_RATE("leave - no private rate data!\n"); - else - IWL_DEBUG_RATE("leave - no station!\n"); - rcu_read_unlock(); - return sprintf(buf, "station %d not found\n", sta_id); - } - - lq_sta = (void *)sta->rate_ctrl_priv; - - lq_type = lq_sta->lq_info[lq_sta->active_tbl].lq_type; - antenna = lq_sta->lq_info[lq_sta->active_tbl].ant_type; - - if (is_legacy(lq_type)) - i = IWL_RATE_54M_INDEX; - else - i = IWL_RATE_60M_INDEX; - while (1) { - u64 mask; - int j; - int active = lq_sta->active_tbl; - - cnt += - sprintf(&buf[cnt], " %2dMbs: ", iwl_rates[i].ieee / 2); - - mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1)); - for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1) - buf[cnt++] = - (lq_sta->lq_info[active].win[i].data & mask) - ? '1' : '0'; - - samples += lq_sta->lq_info[active].win[i].counter; - good += lq_sta->lq_info[active].win[i].success_counter; - success += lq_sta->lq_info[active].win[i].success_counter * - iwl_rates[i].ieee; - - if (lq_sta->lq_info[active].win[i].stamp) { - int delta = - jiffies_to_msecs(now - - lq_sta->lq_info[active].win[i].stamp); - - if (delta > max_time) - max_time = delta; - - cnt += sprintf(&buf[cnt], "%5dms\n", delta); - } else - buf[cnt++] = '\n'; - - j = iwl4965_get_prev_ieee_rate(i); - if (j == i) - break; - i = j; - } - - /* - * Display the average rate of all samples taken. - * NOTE: We multiply # of samples by 2 since the IEEE measurement - * added from iwl_rates is actually 2X the rate. - */ - if (samples) - cnt += sprintf(&buf[cnt], - "\nAverage rate is %3d.%02dMbs over last %4dms\n" - "%3d%% success (%d good packets over %d tries)\n", - success / (2 * samples), (success * 5 / samples) % 10, - max_time, good * 100 / samples, good, samples); - else - cnt += sprintf(&buf[cnt], "\nAverage rate: 0Mbs\n"); - - cnt += sprintf(&buf[cnt], "\nrate scale type %d antenna %d " - "active_search %d rate index %d\n", lq_type, antenna, - lq_sta->search_better_tbl, sta->last_txrate_idx); - - rcu_read_unlock(); - return cnt; -} - int iwlagn_rate_control_register(void) { return ieee80211_rate_control_register(&rs_ops); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 3b06c9da77e..84d4d1e3375 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -286,15 +286,6 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) return rate; } -/** - * iwl4965_fill_rs_info - Fill an output text buffer with the rate representation - * - * NOTE: This is provided as a quick mechanism for a user to visualize - * the performance of the rate control algorithm and is not meant to be - * parsed software. - */ -extern int iwl4965_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id); - /** * iwl4965_rate_control_register - Register the rate control algorithm callbacks * diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index dcd11e9bd86..9db6aac0218 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -3687,15 +3687,6 @@ static ssize_t show_temperature(struct device *d, static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); -static ssize_t show_rs_window(struct device *d, - struct device_attribute *attr, - char *buf) -{ - struct iwl_priv *priv = d->driver_data; - return iwl4965_fill_rs_info(priv->hw, buf, IWL_AP_ID); -} -static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL); - static ssize_t show_tx_power(struct device *d, struct device_attribute *attr, char *buf) { @@ -4118,7 +4109,6 @@ static struct attribute *iwl4965_sysfs_entries[] = { #endif &dev_attr_power_level.attr, &dev_attr_retry_rate.attr, - &dev_attr_rs_window.attr, &dev_attr_statistics.attr, &dev_attr_status.attr, &dev_attr_temperature.attr, -- cgit v1.2.3 From c785d1d5018b93878a9280b0c04df96682cc6eff Mon Sep 17 00:00:00 2001 From: Esti Kummer Date: Fri, 18 Jul 2008 13:53:07 +0800 Subject: iwlwifi: set led register in disassociation This patch sets the led register in disassociation flow according to rf-kill state : off - in case of rf_kill, on - otherwise. Signed-off-by: Esti Kummer Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-led.c | 40 ++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 61250e6a7d1..0a01f091c51 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -161,11 +161,31 @@ int iwl4965_led_off(struct iwl_priv *priv, int led_id) /* Set led register off */ static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id) { - IWL_DEBUG_LED("radio off\n"); + IWL_DEBUG_LED("LED Reg off\n"); iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF); return 0; } +/* + * Set led register in case of disassociation according to rfkill state + */ +static int iwl_led_associate(struct iwl_priv *priv, int led_id) +{ + IWL_DEBUG_LED("Associated\n"); + priv->allow_blinking = 1; + return iwl4965_led_on_reg(priv, led_id); +} +static int iwl_led_disassociate(struct iwl_priv *priv, int led_id) +{ + priv->allow_blinking = 0; + if (iwl_is_rfkill(priv)) + iwl4965_led_off_reg(priv, led_id); + else + iwl4965_led_on_reg(priv, led_id); + + return 0; +} + /* * brightness call back function for Tx/Rx LED */ @@ -199,16 +219,10 @@ static void iwl_led_brightness_set(struct led_classdev *led_cdev, led_type_str[led->type], brightness); switch (brightness) { case LED_FULL: - if (led->type == IWL_LED_TRG_ASSOC) - priv->allow_blinking = 1; - if (led->led_on) led->led_on(priv, IWL_LED_LINK); break; case LED_OFF: - if (led->type == IWL_LED_TRG_ASSOC) - priv->allow_blinking = 0; - if (led->led_off) led->led_off(priv, IWL_LED_LINK); break; @@ -284,12 +298,6 @@ static int iwl_get_blink_rate(struct iwl_priv *priv) return i; } -static inline int is_rf_kill(struct iwl_priv *priv) -{ - return test_bit(STATUS_RF_KILL_HW, &priv->status) || - test_bit(STATUS_RF_KILL_SW, &priv->status); -} - /* * this function called from handler. Since setting Led command can * happen very frequent we postpone led command to be called from @@ -303,7 +311,7 @@ void iwl_leds_background(struct iwl_priv *priv) priv->last_blink_time = 0; return; } - if (is_rf_kill(priv)) { + if (iwl_is_rfkill(priv)) { priv->last_blink_time = 0; return; } @@ -366,8 +374,8 @@ int iwl_leds_register(struct iwl_priv *priv) IWL_LED_TRG_ASSOC, 0, name, trigger); /* for assoc always turn led on */ - priv->led[IWL_LED_TRG_ASSOC].led_on = iwl4965_led_on_reg; - priv->led[IWL_LED_TRG_ASSOC].led_off = iwl4965_led_on_reg; + priv->led[IWL_LED_TRG_ASSOC].led_on = iwl_led_associate; + priv->led[IWL_LED_TRG_ASSOC].led_off = iwl_led_disassociate; priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL; if (ret) -- cgit v1.2.3 From 4aa41f12aa4f08a10b0b07ed334faa3638ba8e9c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Fri, 18 Jul 2008 13:53:09 +0800 Subject: iwlwifi: bug fix in AGG flow - cast const to ULL This patch fixes a bug in AGG flow: u64 bitmap = 0; bitmap |= 1 << 32 results to be 0xffffffff80000000. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl-5000.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index c0ba28fa672..f356f4f0944 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2130,9 +2130,9 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, bitmap = bitmap << sh; sh = 0; } - bitmap |= (1 << sh); - IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n", - start, (u32)(bitmap & 0xFFFFFFFF)); + bitmap |= 1ULL << sh; + IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%llx\n", + start, (unsigned long long)bitmap); } agg->bitmap = bitmap; diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index f91c54b5ff5..076d3560302 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1228,9 +1228,9 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv, bitmap = bitmap << sh; sh = 0; } - bitmap |= (1 << sh); - IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n", - start, (u32)(bitmap & 0xFFFFFFFF)); + bitmap |= 1ULL << sh; + IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%llx\n", + start, (unsigned long long)bitmap); } agg->bitmap = bitmap; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 0182e4da8e3..39f19ebee97 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1391,7 +1391,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv, /* For each frame attempted in aggregation, * update driver's record of tx frame's status. */ for (i = 0; i < agg->frame_count ; i++) { - ack = bitmap & (1 << i); + ack = bitmap & (1ULL << i); successes += !!ack; IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n", ack? "ACK":"NACK", i, (agg->start_idx + i) & 0xff, -- cgit v1.2.3 From e170402e5459c12ed8f5bfaa11e6550eba09e57a Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Sat, 19 Jul 2008 04:04:18 +0300 Subject: iwlwifi: RS small compile warnings without CONFIG_IWLWIFI_DEBUG iwl-agn-rs.c: In function 'rs_clear': iwl-agn-rs.c:2405: warning: unused variable 'priv Signed-off-by: Denis V. Lunev Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 0e8100e7062..b498b58d81f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2393,6 +2393,7 @@ static void rs_free(void *priv_rate) static void rs_clear(void *priv_rate) { +#ifdef CONFIG_IWLWIFI_DEBUG struct iwl_priv *priv = (struct iwl_priv *) priv_rate; IWL_DEBUG_RATE("enter\n"); @@ -2400,6 +2401,7 @@ static void rs_clear(void *priv_rate) /* TODO - add rate scale state reset */ IWL_DEBUG_RATE("leave\n"); +#endif /* CONFIG_IWLWIFI_DEBUG */ } static void rs_free_sta(void *priv_rate, void *priv_sta) -- cgit v1.2.3 From b5d7be5e665f29274cfe6645b661acb38cb1d19b Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sat, 19 Jul 2008 04:41:24 +0300 Subject: iwlwifi: use dtim_period from association, and set listen_interval This patch uses dtim_period from association, and sets the listen_interval. Signed-off-by: Tomas Winkler Signed-off-by: Emmanuel Grumbach Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 3 +-- drivers/net/wireless/iwlwifi/iwl-core.c | 1 + drivers/net/wireless/iwlwifi/iwl4965-base.c | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index cd6d668f4e0..5e57f3ae2ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -666,8 +666,7 @@ struct iwl4965_rxon_assoc_cmd { __le16 reserved; } __attribute__ ((packed)); - - +#define IWL_CONN_MAX_LISTEN_INTERVAL 10 /* * REPLY_RXON_TIMING = 0x14 (command, has simple generic response) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 60d443e77c3..96beacf703a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -827,6 +827,7 @@ int iwl_setup_mac(struct iwl_priv *priv) hw->ampdu_queues = priv->cfg->mod_params->num_of_ampdu_queues; hw->conf.beacon_int = 100; + hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 9db6aac0218..f71b3f3f81b 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -639,7 +639,6 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force) } #define MAX_UCODE_BEACON_INTERVAL 4096 -#define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA) static __le16 iwl4965_adjust_beacon_interval(u16 beacon_val) { @@ -669,7 +668,7 @@ static void iwl4965_setup_rxon_timing(struct iwl_priv *priv) priv->rxon_timing.timestamp.dw[0] = cpu_to_le32(priv->timestamp & 0xFFFFFFFF); - priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL; + priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval); tsf = priv->timestamp; @@ -2835,6 +2834,7 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co spin_lock_irqsave(&priv->lock, flags); + /* if we are switching from ht to 2.4 clear flags * from any ht related info since 2.4 does not * support ht */ @@ -3164,6 +3164,7 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, if (bss_conf->assoc) { priv->assoc_id = bss_conf->aid; priv->beacon_int = bss_conf->beacon_int; + priv->power_data.dtim_period = bss_conf->dtim_period; priv->timestamp = bss_conf->timestamp; priv->assoc_capability = bss_conf->assoc_capability; priv->next_scan_jiffies = jiffies + -- cgit v1.2.3 From 25bc2deda9e8a430ed49f507a1120fb2c86abf33 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 21 Jul 2008 02:40:13 +0300 Subject: iwlwifi: rename iwl4965-base.c to iwl-agn.c This patch renames iwl4965-base.c to iwl-agn.c Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Makefile | 6 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 4523 +++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 4523 --------------------------- 3 files changed, 4525 insertions(+), 4527 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-agn.c delete mode 100644 drivers/net/wireless/iwlwifi/iwl4965-base.c (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index f50d2f8fd5c..6bf3998736b 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -11,10 +11,8 @@ iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl3945-$(CONFIG_IWL3945_LEDS) += iwl-3945-led.o obj-$(CONFIG_IWL4965) += iwl4965.o -iwl4965-objs := iwl4965-base.o iwl-4965.o iwl-agn-rs.o +iwl4965-objs := iwl-agn.o iwl-4965.o iwl-agn-rs.o -ifeq ($(CONFIG_IWL5000),y) - iwl4965-objs += iwl-5000.o -endif +iwl4965-$(CONFIG_IWL5000) += iwl-5000.o diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c new file mode 100644 index 00000000000..f71b3f3f81b --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -0,0 +1,4523 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "iwl-eeprom.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-io.h" +#include "iwl-helpers.h" +#include "iwl-sta.h" +#include "iwl-calib.h" + + +/****************************************************************************** + * + * module boiler plate + * + ******************************************************************************/ + +/* + * module name, copyright, version, etc. + * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk + */ + +#define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link AGN driver for Linux" + +#ifdef CONFIG_IWLWIFI_DEBUG +#define VD "d" +#else +#define VD +#endif + +#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT +#define VS "s" +#else +#define VS +#endif + +#define DRV_VERSION IWLWIFI_VERSION VD VS + + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_LICENSE("GPL"); + +/*************** STATION TABLE MANAGEMENT **** + * mac80211 should be examined to determine if sta_info is duplicating + * the functionality provided here + */ + +/**************************************************************/ + + + +static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) +{ + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; + + if (hw_decrypt) + rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; + else + rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK; + +} + +/** + * iwl4965_check_rxon_cmd - validate RXON structure is valid + * + * NOTE: This is really only useful during development and can eventually + * be #ifdef'd out once the driver is stable and folks aren't actively + * making changes + */ +static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon) +{ + int error = 0; + int counter = 1; + + if (rxon->flags & RXON_FLG_BAND_24G_MSK) { + error |= le32_to_cpu(rxon->flags & + (RXON_FLG_TGJ_NARROW_BAND_MSK | + RXON_FLG_RADAR_DETECT_MSK)); + if (error) + IWL_WARNING("check 24G fields %d | %d\n", + counter++, error); + } else { + error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ? + 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK); + if (error) + IWL_WARNING("check 52 fields %d | %d\n", + counter++, error); + error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK); + if (error) + IWL_WARNING("check 52 CCK %d | %d\n", + counter++, error); + } + error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1; + if (error) + IWL_WARNING("check mac addr %d | %d\n", counter++, error); + + /* make sure basic rates 6Mbps and 1Mbps are supported */ + error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) && + ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0)); + if (error) + IWL_WARNING("check basic rate %d | %d\n", counter++, error); + + error |= (le16_to_cpu(rxon->assoc_id) > 2007); + if (error) + IWL_WARNING("check assoc id %d | %d\n", counter++, error); + + error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)); + if (error) + IWL_WARNING("check CCK and short slot %d | %d\n", + counter++, error); + + error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)); + if (error) + IWL_WARNING("check CCK & auto detect %d | %d\n", + counter++, error); + + error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | + RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK); + if (error) + IWL_WARNING("check TGG and auto detect %d | %d\n", + counter++, error); + + if (error) + IWL_WARNING("Tuning to channel %d\n", + le16_to_cpu(rxon->channel)); + + if (error) { + IWL_ERROR("Not a valid iwl4965_rxon_assoc_cmd field values\n"); + return -1; + } + return 0; +} + +/** + * iwl4965_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed + * @priv: staging_rxon is compared to active_rxon + * + * If the RXON structure is changing enough to require a new tune, + * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that + * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required. + */ +static int iwl4965_full_rxon_required(struct iwl_priv *priv) +{ + + /* These items are only settable from the full RXON command */ + if (!(iwl_is_associated(priv)) || + compare_ether_addr(priv->staging_rxon.bssid_addr, + priv->active_rxon.bssid_addr) || + compare_ether_addr(priv->staging_rxon.node_addr, + priv->active_rxon.node_addr) || + compare_ether_addr(priv->staging_rxon.wlap_bssid_addr, + priv->active_rxon.wlap_bssid_addr) || + (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) || + (priv->staging_rxon.channel != priv->active_rxon.channel) || + (priv->staging_rxon.air_propagation != + priv->active_rxon.air_propagation) || + (priv->staging_rxon.ofdm_ht_single_stream_basic_rates != + priv->active_rxon.ofdm_ht_single_stream_basic_rates) || + (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates != + priv->active_rxon.ofdm_ht_dual_stream_basic_rates) || + (priv->staging_rxon.rx_chain != priv->active_rxon.rx_chain) || + (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id)) + return 1; + + /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can + * be updated with the RXON_ASSOC command -- however only some + * flag transitions are allowed using RXON_ASSOC */ + + /* Check if we are not switching bands */ + if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) != + (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)) + return 1; + + /* Check if we are switching association toggle */ + if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) != + (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) + return 1; + + return 0; +} + +/** + * iwl4965_commit_rxon - commit staging_rxon to hardware + * + * The RXON command in staging_rxon is committed to the hardware and + * the active_rxon structure is updated with the new data. This + * function correctly transitions out of the RXON_ASSOC_MSK state if + * a HW tune is required based on the RXON structure changes. + */ +static int iwl4965_commit_rxon(struct iwl_priv *priv) +{ + /* cast away the const for active_rxon in this function */ + struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; + DECLARE_MAC_BUF(mac); + int ret; + bool new_assoc = + !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK); + + if (!iwl_is_alive(priv)) + return -EBUSY; + + /* always get timestamp with Rx frame */ + priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; + /* allow CTS-to-self if possible. this is relevant only for + * 5000, but will not damage 4965 */ + priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN; + + ret = iwl4965_check_rxon_cmd(&priv->staging_rxon); + if (ret) { + IWL_ERROR("Invalid RXON configuration. Not committing.\n"); + return -EINVAL; + } + + /* If we don't need to send a full RXON, we can use + * iwl4965_rxon_assoc_cmd which is used to reconfigure filter + * and other flags for the current radio configuration. */ + if (!iwl4965_full_rxon_required(priv)) { + ret = iwl_send_rxon_assoc(priv); + if (ret) { + IWL_ERROR("Error setting RXON_ASSOC (%d)\n", ret); + return ret; + } + + memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); + return 0; + } + + /* station table will be cleared */ + priv->assoc_station_added = 0; + + /* If we are currently associated and the new config requires + * an RXON_ASSOC and the new config wants the associated mask enabled, + * we must clear the associated from the active configuration + * before we apply the new config */ + if (iwl_is_associated(priv) && new_assoc) { + IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); + active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; + + ret = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl_rxon_cmd), + &priv->active_rxon); + + /* If the mask clearing failed then we set + * active_rxon back to what it was previously */ + if (ret) { + active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; + IWL_ERROR("Error clearing ASSOC_MSK (%d)\n", ret); + return ret; + } + } + + IWL_DEBUG_INFO("Sending RXON\n" + "* with%s RXON_FILTER_ASSOC_MSK\n" + "* channel = %d\n" + "* bssid = %s\n", + (new_assoc ? "" : "out"), + le16_to_cpu(priv->staging_rxon.channel), + print_mac(mac, priv->staging_rxon.bssid_addr)); + + iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); + + /* Apply the new configuration + * RXON unassoc clears the station table in uCode, send it before + * we add the bcast station. If assoc bit is set, we will send RXON + * after having added the bcast and bssid station. + */ + if (!new_assoc) { + ret = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); + if (ret) { + IWL_ERROR("Error setting new RXON (%d)\n", ret); + return ret; + } + memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); + } + + iwl_clear_stations_table(priv); + + if (!priv->error_recovering) + priv->start_calib = 0; + + /* Add the broadcast address so we can send broadcast frames */ + if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) == + IWL_INVALID_STATION) { + IWL_ERROR("Error adding BROADCAST address for transmit.\n"); + return -EIO; + } + + /* If we have set the ASSOC_MSK and we are in BSS mode then + * add the IWL_AP_ID to the station rate table */ + if (new_assoc) { + if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + ret = iwl_rxon_add_station(priv, + priv->active_rxon.bssid_addr, 1); + if (ret == IWL_INVALID_STATION) { + IWL_ERROR("Error adding AP address for TX.\n"); + return -EIO; + } + priv->assoc_station_added = 1; + if (priv->default_wep_key && + iwl_send_static_wepkey_cmd(priv, 0)) + IWL_ERROR("Could not send WEP static key.\n"); + } + + /* Apply the new configuration + * RXON assoc doesn't clear the station table in uCode, + */ + ret = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); + if (ret) { + IWL_ERROR("Error setting new RXON (%d)\n", ret); + return ret; + } + memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); + } + + iwl_init_sensitivity(priv); + + /* If we issue a new RXON command which required a tune then we must + * send a new TXPOWER command or we won't be able to Tx any frames */ + ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); + if (ret) { + IWL_ERROR("Error sending TX power (%d)\n", ret); + return ret; + } + + return 0; +} + +void iwl4965_update_chain_flags(struct iwl_priv *priv) +{ + + iwl_set_rxon_chain(priv); + iwl4965_commit_rxon(priv); +} + +static int iwl4965_send_bt_config(struct iwl_priv *priv) +{ + struct iwl4965_bt_cmd bt_cmd = { + .flags = 3, + .lead_time = 0xAA, + .max_kill = 1, + .kill_ack_mask = 0, + .kill_cts_mask = 0, + }; + + return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, + sizeof(struct iwl4965_bt_cmd), &bt_cmd); +} + +static void iwl_clear_free_frames(struct iwl_priv *priv) +{ + struct list_head *element; + + IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n", + priv->frames_count); + + while (!list_empty(&priv->free_frames)) { + element = priv->free_frames.next; + list_del(element); + kfree(list_entry(element, struct iwl_frame, list)); + priv->frames_count--; + } + + if (priv->frames_count) { + IWL_WARNING("%d frames still in use. Did we lose one?\n", + priv->frames_count); + priv->frames_count = 0; + } +} + +static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) +{ + struct iwl_frame *frame; + struct list_head *element; + if (list_empty(&priv->free_frames)) { + frame = kzalloc(sizeof(*frame), GFP_KERNEL); + if (!frame) { + IWL_ERROR("Could not allocate frame!\n"); + return NULL; + } + + priv->frames_count++; + return frame; + } + + element = priv->free_frames.next; + list_del(element); + return list_entry(element, struct iwl_frame, list); +} + +static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) +{ + memset(frame, 0, sizeof(*frame)); + list_add(&frame->list, &priv->free_frames); +} + +static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, + struct ieee80211_hdr *hdr, + const u8 *dest, int left) +{ + if (!iwl_is_associated(priv) || !priv->ibss_beacon || + ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) && + (priv->iw_mode != IEEE80211_IF_TYPE_AP))) + return 0; + + if (priv->ibss_beacon->len > left) + return 0; + + memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len); + + return priv->ibss_beacon->len; +} + +static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) +{ + int i; + int rate_mask; + + /* Set rate mask*/ + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) + rate_mask = priv->active_rate_basic & 0xF; + else + rate_mask = priv->active_rate_basic & 0xFF0; + + /* Find lowest valid rate */ + for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; + i = iwl_rates[i].next_ieee) { + if (rate_mask & (1 << i)) + return iwl_rates[i].plcp; + } + + /* No valid rate was found. Assign the lowest one */ + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) + return IWL_RATE_1M_PLCP; + else + return IWL_RATE_6M_PLCP; +} + +unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, + struct iwl_frame *frame, u8 rate) +{ + struct iwl_tx_beacon_cmd *tx_beacon_cmd; + unsigned int frame_size; + + tx_beacon_cmd = &frame->u.beacon; + memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); + + tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id; + tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + + frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame, + iwl_bcast_addr, + sizeof(frame->u) - sizeof(*tx_beacon_cmd)); + + BUG_ON(frame_size > MAX_MPDU_SIZE); + tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); + + if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP)) + tx_beacon_cmd->tx.rate_n_flags = + iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK); + else + tx_beacon_cmd->tx.rate_n_flags = + iwl_hw_set_rate_n_flags(rate, 0); + + tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK | + TX_CMD_FLG_TSF_MSK | + TX_CMD_FLG_STA_RATE_MSK; + + return sizeof(*tx_beacon_cmd) + frame_size; +} +static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) +{ + struct iwl_frame *frame; + unsigned int frame_size; + int rc; + u8 rate; + + frame = iwl_get_free_frame(priv); + + if (!frame) { + IWL_ERROR("Could not obtain free frame buffer for beacon " + "command.\n"); + return -ENOMEM; + } + + rate = iwl4965_rate_get_lowest_plcp(priv); + + frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate); + + rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, + &frame->u.cmd[0]); + + iwl_free_frame(priv, frame); + + return rc; +} + +/****************************************************************************** + * + * Misc. internal state and helper functions + * + ******************************************************************************/ + +static void iwl4965_ht_conf(struct iwl_priv *priv, + struct ieee80211_bss_conf *bss_conf) +{ + struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf; + struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf; + struct iwl_ht_info *iwl_conf = &priv->current_ht_config; + + IWL_DEBUG_MAC80211("enter: \n"); + + iwl_conf->is_ht = bss_conf->assoc_ht; + + if (!iwl_conf->is_ht) + return; + + priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); + + if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) + iwl_conf->sgf |= HT_SHORT_GI_20MHZ; + if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) + iwl_conf->sgf |= HT_SHORT_GI_40MHZ; + + iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); + iwl_conf->max_amsdu_size = + !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); + + iwl_conf->supported_chan_width = + !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH); + iwl_conf->extension_chan_offset = + ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET; + /* If no above or below channel supplied disable FAT channel */ + if (iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_ABOVE && + iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_BELOW) { + iwl_conf->extension_chan_offset = IEEE80211_HT_IE_CHA_SEC_NONE; + iwl_conf->supported_chan_width = 0; + } + + iwl_conf->tx_mimo_ps_mode = + (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); + memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); + + iwl_conf->control_channel = ht_bss_conf->primary_channel; + iwl_conf->tx_chan_width = + !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH); + iwl_conf->ht_protection = + ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION; + iwl_conf->non_GF_STA_present = + !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT); + + IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel); + IWL_DEBUG_MAC80211("leave\n"); +} + +/* + * QoS support +*/ +static void iwl_activate_qos(struct iwl_priv *priv, u8 force) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + if (!priv->qos_data.qos_enable) + return; + + priv->qos_data.def_qos_parm.qos_flags = 0; + + if (priv->qos_data.qos_cap.q_AP.queue_request && + !priv->qos_data.qos_cap.q_AP.txop_request) + priv->qos_data.def_qos_parm.qos_flags |= + QOS_PARAM_FLG_TXOP_TYPE_MSK; + if (priv->qos_data.qos_active) + priv->qos_data.def_qos_parm.qos_flags |= + QOS_PARAM_FLG_UPDATE_EDCA_MSK; + + if (priv->current_ht_config.is_ht) + priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; + + if (force || iwl_is_associated(priv)) { + IWL_DEBUG_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n", + priv->qos_data.qos_active, + priv->qos_data.def_qos_parm.qos_flags); + + iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM, + sizeof(struct iwl_qosparam_cmd), + &priv->qos_data.def_qos_parm, NULL); + } +} + +#define MAX_UCODE_BEACON_INTERVAL 4096 + +static __le16 iwl4965_adjust_beacon_interval(u16 beacon_val) +{ + u16 new_val = 0; + u16 beacon_factor = 0; + + beacon_factor = + (beacon_val + MAX_UCODE_BEACON_INTERVAL) + / MAX_UCODE_BEACON_INTERVAL; + new_val = beacon_val / beacon_factor; + + return cpu_to_le16(new_val); +} + +static void iwl4965_setup_rxon_timing(struct iwl_priv *priv) +{ + u64 interval_tm_unit; + u64 tsf, result; + unsigned long flags; + struct ieee80211_conf *conf = NULL; + u16 beacon_int = 0; + + conf = ieee80211_get_hw_conf(priv->hw); + + spin_lock_irqsave(&priv->lock, flags); + priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp >> 32); + priv->rxon_timing.timestamp.dw[0] = + cpu_to_le32(priv->timestamp & 0xFFFFFFFF); + + priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval); + + tsf = priv->timestamp; + + beacon_int = priv->beacon_int; + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + if (beacon_int == 0) { + priv->rxon_timing.beacon_interval = cpu_to_le16(100); + priv->rxon_timing.beacon_init_val = cpu_to_le32(102400); + } else { + priv->rxon_timing.beacon_interval = + cpu_to_le16(beacon_int); + priv->rxon_timing.beacon_interval = + iwl4965_adjust_beacon_interval( + le16_to_cpu(priv->rxon_timing.beacon_interval)); + } + + priv->rxon_timing.atim_window = 0; + } else { + priv->rxon_timing.beacon_interval = + iwl4965_adjust_beacon_interval(conf->beacon_int); + /* TODO: we need to get atim_window from upper stack + * for now we set to 0 */ + priv->rxon_timing.atim_window = 0; + } + + interval_tm_unit = + (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024); + result = do_div(tsf, interval_tm_unit); + priv->rxon_timing.beacon_init_val = + cpu_to_le32((u32) ((u64) interval_tm_unit - result)); + + IWL_DEBUG_ASSOC + ("beacon interval %d beacon timer %d beacon tim %d\n", + le16_to_cpu(priv->rxon_timing.beacon_interval), + le32_to_cpu(priv->rxon_timing.beacon_init_val), + le16_to_cpu(priv->rxon_timing.atim_window)); +} + +static void iwl_set_flags_for_band(struct iwl_priv *priv, + enum ieee80211_band band) +{ + if (band == IEEE80211_BAND_5GHZ) { + priv->staging_rxon.flags &= + ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK + | RXON_FLG_CCK_MSK); + priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; + } else { + /* Copied from iwl4965_post_associate() */ + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) + priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; + priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK; + priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK; + } +} + +/* + * initialize rxon structure with default values from eeprom + */ +static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) +{ + const struct iwl_channel_info *ch_info; + + memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); + + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_AP: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; + break; + + case IEEE80211_IF_TYPE_STA: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS; + priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; + break; + + case IEEE80211_IF_TYPE_IBSS: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS; + priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK; + priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK | + RXON_FILTER_ACCEPT_GRP_MSK; + break; + + case IEEE80211_IF_TYPE_MNTR: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER; + priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK | + RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; + break; + default: + IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode); + break; + } + +#if 0 + /* TODO: Figure out when short_preamble would be set and cache from + * that */ + if (!hw_to_local(priv->hw)->short_preamble) + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; +#endif + + ch_info = iwl_get_channel_info(priv, priv->band, + le16_to_cpu(priv->active_rxon.channel)); + + if (!ch_info) + ch_info = &priv->channel_info[0]; + + /* + * in some case A channels are all non IBSS + * in this case force B/G channel + */ + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + !(is_channel_ibss(ch_info))) + ch_info = &priv->channel_info[0]; + + priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); + priv->band = ch_info->band; + + iwl_set_flags_for_band(priv, priv->band); + + priv->staging_rxon.ofdm_basic_rates = + (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; + priv->staging_rxon.cck_basic_rates = + (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; + + priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | + RXON_FLG_CHANNEL_MODE_PURE_40_MSK); + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); + memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN); + priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff; + priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff; + iwl_set_rxon_chain(priv); +} + +static int iwl4965_set_mode(struct iwl_priv *priv, int mode) +{ + priv->iw_mode = mode; + + iwl4965_connection_init_rx_config(priv); + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); + + iwl_clear_stations_table(priv); + + /* dont commit rxon if rf-kill is on*/ + if (!iwl_is_ready_rf(priv)) + return -EAGAIN; + + cancel_delayed_work(&priv->scan_check); + if (iwl_scan_cancel_timeout(priv, 100)) { + IWL_WARNING("Aborted scan still in progress after 100ms\n"); + IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); + return -EAGAIN; + } + + iwl4965_commit_rxon(priv); + + return 0; +} + +static void iwl4965_set_rate(struct iwl_priv *priv) +{ + const struct ieee80211_supported_band *hw = NULL; + struct ieee80211_rate *rate; + int i; + + hw = iwl_get_hw_mode(priv, priv->band); + if (!hw) { + IWL_ERROR("Failed to set rate: unable to get hw mode\n"); + return; + } + + priv->active_rate = 0; + priv->active_rate_basic = 0; + + for (i = 0; i < hw->n_bitrates; i++) { + rate = &(hw->bitrates[i]); + if (rate->hw_value < IWL_RATE_COUNT) + priv->active_rate |= (1 << rate->hw_value); + } + + IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n", + priv->active_rate, priv->active_rate_basic); + + /* + * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK) + * otherwise set it to the default of all CCK rates and 6, 12, 24 for + * OFDM + */ + if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK) + priv->staging_rxon.cck_basic_rates = + ((priv->active_rate_basic & + IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF; + else + priv->staging_rxon.cck_basic_rates = + (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; + + if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK) + priv->staging_rxon.ofdm_basic_rates = + ((priv->active_rate_basic & + (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >> + IWL_FIRST_OFDM_RATE) & 0xFF; + else + priv->staging_rxon.ofdm_basic_rates = + (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; +} + +#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT + +#include "iwl-spectrum.h" + +#define BEACON_TIME_MASK_LOW 0x00FFFFFF +#define BEACON_TIME_MASK_HIGH 0xFF000000 +#define TIME_UNIT 1024 + +/* + * extended beacon time format + * time in usec will be changed into a 32-bit value in 8:24 format + * the high 1 byte is the beacon counts + * the lower 3 bytes is the time in usec within one beacon interval + */ + +static u32 iwl4965_usecs_to_beacons(u32 usec, u32 beacon_interval) +{ + u32 quot; + u32 rem; + u32 interval = beacon_interval * 1024; + + if (!interval || !usec) + return 0; + + quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24); + rem = (usec % interval) & BEACON_TIME_MASK_LOW; + + return (quot << 24) + rem; +} + +/* base is usually what we get from ucode with each received frame, + * the same as HW timer counter counting down + */ + +static __le32 iwl4965_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) +{ + u32 base_low = base & BEACON_TIME_MASK_LOW; + u32 addon_low = addon & BEACON_TIME_MASK_LOW; + u32 interval = beacon_interval * TIME_UNIT; + u32 res = (base & BEACON_TIME_MASK_HIGH) + + (addon & BEACON_TIME_MASK_HIGH); + + if (base_low > addon_low) + res += base_low - addon_low; + else if (base_low < addon_low) { + res += interval + base_low - addon_low; + res += (1 << 24); + } else + res += (1 << 24); + + return cpu_to_le32(res); +} + +static int iwl4965_get_measurement(struct iwl_priv *priv, + struct ieee80211_measurement_params *params, + u8 type) +{ + struct iwl4965_spectrum_cmd spectrum; + struct iwl_rx_packet *res; + struct iwl_host_cmd cmd = { + .id = REPLY_SPECTRUM_MEASUREMENT_CMD, + .data = (void *)&spectrum, + .meta.flags = CMD_WANT_SKB, + }; + u32 add_time = le64_to_cpu(params->start_time); + int rc; + int spectrum_resp_status; + int duration = le16_to_cpu(params->duration); + + if (iwl_is_associated(priv)) + add_time = + iwl4965_usecs_to_beacons( + le64_to_cpu(params->start_time) - priv->last_tsf, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + + memset(&spectrum, 0, sizeof(spectrum)); + + spectrum.channel_count = cpu_to_le16(1); + spectrum.flags = + RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK; + spectrum.filter_flags = MEASUREMENT_FILTER_FLAG; + cmd.len = sizeof(spectrum); + spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); + + if (iwl_is_associated(priv)) + spectrum.start_time = + iwl4965_add_beacon_time(priv->last_beacon_time, + add_time, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + else + spectrum.start_time = 0; + + spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT); + spectrum.channels[0].channel = params->channel; + spectrum.channels[0].type = type; + if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK) + spectrum.flags |= RXON_FLG_BAND_24G_MSK | + RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n"); + rc = -EIO; + } + + spectrum_resp_status = le16_to_cpu(res->u.spectrum.status); + switch (spectrum_resp_status) { + case 0: /* Command will be handled */ + if (res->u.spectrum.id != 0xff) { + IWL_DEBUG_INFO + ("Replaced existing measurement: %d\n", + res->u.spectrum.id); + priv->measurement_status &= ~MEASUREMENT_READY; + } + priv->measurement_status |= MEASUREMENT_ACTIVE; + rc = 0; + break; + + case 1: /* Command will not be handled */ + rc = -EAGAIN; + break; + } + + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} +#endif + +/****************************************************************************** + * + * Generic RX handler implementations + * + ******************************************************************************/ +static void iwl_rx_reply_alive(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_alive_resp *palive; + struct delayed_work *pwork; + + palive = &pkt->u.alive_frame; + + IWL_DEBUG_INFO("Alive ucode status 0x%08X revision " + "0x%01X 0x%01X\n", + palive->is_valid, palive->ver_type, + palive->ver_subtype); + + if (palive->ver_subtype == INITIALIZE_SUBTYPE) { + IWL_DEBUG_INFO("Initialization Alive received.\n"); + memcpy(&priv->card_alive_init, + &pkt->u.alive_frame, + sizeof(struct iwl_init_alive_resp)); + pwork = &priv->init_alive_start; + } else { + IWL_DEBUG_INFO("Runtime Alive received.\n"); + memcpy(&priv->card_alive, &pkt->u.alive_frame, + sizeof(struct iwl_alive_resp)); + pwork = &priv->alive_start; + } + + /* We delay the ALIVE response by 5ms to + * give the HW RF Kill time to activate... */ + if (palive->is_valid == UCODE_VALID_OK) + queue_delayed_work(priv->workqueue, pwork, + msecs_to_jiffies(5)); + else + IWL_WARNING("uCode did not respond OK.\n"); +} + +static void iwl4965_rx_reply_error(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + + IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) " + "seq 0x%04X ser 0x%08X\n", + le32_to_cpu(pkt->u.err_resp.error_type), + get_cmd_string(pkt->u.err_resp.cmd_id), + pkt->u.err_resp.cmd_id, + le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num), + le32_to_cpu(pkt->u.err_resp.error_info)); +} + +#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x + +static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; + struct iwl4965_csa_notification *csa = &(pkt->u.csa_notif); + IWL_DEBUG_11H("CSA notif: channel %d, status %d\n", + le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); + rxon->channel = csa->channel; + priv->staging_rxon.channel = csa->channel; +} + +static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif); + + if (!report->state) { + IWL_DEBUG(IWL_DL_11H, + "Spectrum Measure Notification: Start\n"); + return; + } + + memcpy(&priv->measure_report, report, sizeof(*report)); + priv->measurement_status |= MEASUREMENT_READY; +#endif +} + +static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl4965_sleep_notification *sleep = &(pkt->u.sleep_notif); + IWL_DEBUG_RX("sleep mode: %d, src: %d\n", + sleep->pm_sleep_mode, sleep->pm_wakeup_src); +#endif +} + +static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + IWL_DEBUG_RADIO("Dumping %d bytes of unhandled " + "notification for %s:\n", + le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); + iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); +} + +static void iwl4965_bg_beacon_update(struct work_struct *work) +{ + struct iwl_priv *priv = + container_of(work, struct iwl_priv, beacon_update); + struct sk_buff *beacon; + + /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ + beacon = ieee80211_beacon_get(priv->hw, priv->vif); + + if (!beacon) { + IWL_ERROR("update beacon failed\n"); + return; + } + + mutex_lock(&priv->mutex); + /* new beacon skb is allocated every time; dispose previous.*/ + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = beacon; + mutex_unlock(&priv->mutex); + + iwl4965_send_beacon_cmd(priv); +} + +/** + * iwl4965_bg_statistics_periodic - Timer callback to queue statistics + * + * This callback is provided in order to send a statistics request. + * + * This timer function is continually reset to execute within + * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION + * was received. We need to ensure we receive the statistics in order + * to update the temperature used for calibrating the TXPOWER. + */ +static void iwl4965_bg_statistics_periodic(unsigned long data) +{ + struct iwl_priv *priv = (struct iwl_priv *)data; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + iwl_send_statistics_request(priv, CMD_ASYNC); +} + +static void iwl4965_rx_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl4965_beacon_notif *beacon = &(pkt->u.beacon_status); + u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); + + IWL_DEBUG_RX("beacon status %x retries %d iss %d " + "tsf %d %d rate %d\n", + le32_to_cpu(beacon->beacon_notify_hdr.u.status) & TX_STATUS_MSK, + beacon->beacon_notify_hdr.failure_frame, + le32_to_cpu(beacon->ibss_mgr_status), + le32_to_cpu(beacon->high_tsf), + le32_to_cpu(beacon->low_tsf), rate); +#endif + + if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + (!test_bit(STATUS_EXIT_PENDING, &priv->status))) + queue_work(priv->workqueue, &priv->beacon_update); +} + +/* Handle notification from uCode that card's power state is changing + * due to software, hardware, or critical temperature RFKILL */ +static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); + unsigned long status = priv->status; + + IWL_DEBUG_RF_KILL("Card state received: HW:%s SW:%s\n", + (flags & HW_CARD_DISABLED) ? "Kill" : "On", + (flags & SW_CARD_DISABLED) ? "Kill" : "On"); + + if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | + RF_CARD_DISABLED)) { + + iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + + if (!iwl_grab_nic_access(priv)) { + iwl_write_direct32( + priv, HBUS_TARG_MBX_C, + HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); + + iwl_release_nic_access(priv); + } + + if (!(flags & RXON_CARD_DISABLED)) { + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + if (!iwl_grab_nic_access(priv)) { + iwl_write_direct32( + priv, HBUS_TARG_MBX_C, + HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); + + iwl_release_nic_access(priv); + } + } + + if (flags & RF_CARD_DISABLED) { + iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); + iwl_read32(priv, CSR_UCODE_DRV_GP1); + if (!iwl_grab_nic_access(priv)) + iwl_release_nic_access(priv); + } + } + + if (flags & HW_CARD_DISABLED) + set_bit(STATUS_RF_KILL_HW, &priv->status); + else + clear_bit(STATUS_RF_KILL_HW, &priv->status); + + + if (flags & SW_CARD_DISABLED) + set_bit(STATUS_RF_KILL_SW, &priv->status); + else + clear_bit(STATUS_RF_KILL_SW, &priv->status); + + if (!(flags & RXON_CARD_DISABLED)) + iwl_scan_cancel(priv); + + if ((test_bit(STATUS_RF_KILL_HW, &status) != + test_bit(STATUS_RF_KILL_HW, &priv->status)) || + (test_bit(STATUS_RF_KILL_SW, &status) != + test_bit(STATUS_RF_KILL_SW, &priv->status))) + queue_work(priv->workqueue, &priv->rf_kill); + else + wake_up_interruptible(&priv->wait_command_queue); +} + +int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + ret = iwl_grab_nic_access(priv); + if (ret) + goto err; + + if (src == IWL_PWR_SRC_VAUX) { + u32 val; + ret = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE, + &val); + + if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) + iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VAUX, + ~APMG_PS_CTRL_MSK_PWR_SRC); + } else { + iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, + ~APMG_PS_CTRL_MSK_PWR_SRC); + } + + iwl_release_nic_access(priv); +err: + spin_unlock_irqrestore(&priv->lock, flags); + return ret; +} + +/** + * iwl4965_setup_rx_handlers - Initialize Rx handler callbacks + * + * Setup the RX handlers for each of the reply types sent from the uCode + * to the host. + * + * This function chains into the hardware specific files for them to setup + * any hardware specific handlers as well. + */ +static void iwl_setup_rx_handlers(struct iwl_priv *priv) +{ + priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; + priv->rx_handlers[REPLY_ERROR] = iwl4965_rx_reply_error; + priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl4965_rx_csa; + priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = + iwl4965_rx_spectrum_measure_notif; + priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl4965_rx_pm_sleep_notif; + priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = + iwl4965_rx_pm_debug_statistics_notif; + priv->rx_handlers[BEACON_NOTIFICATION] = iwl4965_rx_beacon_notif; + + /* + * The same handler is used for both the REPLY to a discrete + * statistics request from the host as well as for the periodic + * statistics notifications (after received beacons) from the uCode. + */ + priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_rx_statistics; + priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; + + iwl_setup_rx_scan_handlers(priv); + + /* status change handler */ + priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif; + + priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = + iwl_rx_missed_beacon_notif; + /* Rx handlers */ + priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl_rx_reply_rx_phy; + priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl_rx_reply_rx; + /* block ack */ + priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl_rx_reply_compressed_ba; + /* Set up hardware specific Rx handlers */ + priv->cfg->ops->lib->rx_handler_setup(priv); +} + +/* + * this should be called while priv->lock is locked +*/ +static void __iwl_rx_replenish(struct iwl_priv *priv) +{ + iwl_rx_allocate(priv); + iwl_rx_queue_restock(priv); +} + + +/** + * iwl_rx_handle - Main entry function for receiving responses from uCode + * + * Uses the priv->rx_handlers callback function array to invoke + * the appropriate handlers, including command responses, + * frame-received notifications, and other notifications. + */ +void iwl_rx_handle(struct iwl_priv *priv) +{ + struct iwl_rx_mem_buffer *rxb; + struct iwl_rx_packet *pkt; + struct iwl_rx_queue *rxq = &priv->rxq; + u32 r, i; + int reclaim; + unsigned long flags; + u8 fill_rx = 0; + u32 count = 8; + + /* uCode's read index (stored in shared DRAM) indicates the last Rx + * buffer that the driver may process (last buffer filled by ucode). */ + r = priv->cfg->ops->lib->shared_mem_rx_idx(priv); + i = rxq->read; + + /* Rx interrupt, but nothing sent from uCode */ + if (i == r) + IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d\n", r, i); + + if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) + fill_rx = 1; + + while (i != r) { + rxb = rxq->queue[i]; + + /* If an RXB doesn't have a Rx queue slot associated with it, + * then a bug has been introduced in the queue refilling + * routines -- catch it here */ + BUG_ON(rxb == NULL); + + rxq->queue[i] = NULL; + + pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, + priv->hw_params.rx_buf_size, + PCI_DMA_FROMDEVICE); + pkt = (struct iwl_rx_packet *)rxb->skb->data; + + /* Reclaim a command buffer only if this packet is a response + * to a (driver-originated) command. + * If the packet (e.g. Rx frame) originated from uCode, + * there is no command buffer to reclaim. + * Ucode should set SEQ_RX_FRAME bit if ucode-originated, + * but apparently a few don't get set; catch them here. */ + reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && + (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && + (pkt->hdr.cmd != REPLY_RX) && + (pkt->hdr.cmd != REPLY_COMPRESSED_BA) && + (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && + (pkt->hdr.cmd != REPLY_TX); + + /* Based on type of command response or notification, + * handle those that need handling via function in + * rx_handlers table. See iwl4965_setup_rx_handlers() */ + if (priv->rx_handlers[pkt->hdr.cmd]) { + IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d, %s, 0x%02x\n", r, + i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); + priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); + } else { + /* No handling needed */ + IWL_DEBUG(IWL_DL_RX, + "r %d i %d No handler needed for %s, 0x%02x\n", + r, i, get_cmd_string(pkt->hdr.cmd), + pkt->hdr.cmd); + } + + if (reclaim) { + /* Invoke any callbacks, transfer the skb to caller, and + * fire off the (possibly) blocking iwl_send_cmd() + * as we reclaim the driver command queue */ + if (rxb && rxb->skb) + iwl_tx_cmd_complete(priv, rxb); + else + IWL_WARNING("Claim null rxb?\n"); + } + + /* For now we just don't re-use anything. We can tweak this + * later to try and re-use notification packets and SKBs that + * fail to Rx correctly */ + if (rxb->skb != NULL) { + priv->alloc_rxb_skb--; + dev_kfree_skb_any(rxb->skb); + rxb->skb = NULL; + } + + pci_unmap_single(priv->pci_dev, rxb->dma_addr, + priv->hw_params.rx_buf_size, + PCI_DMA_FROMDEVICE); + spin_lock_irqsave(&rxq->lock, flags); + list_add_tail(&rxb->list, &priv->rxq.rx_used); + spin_unlock_irqrestore(&rxq->lock, flags); + i = (i + 1) & RX_QUEUE_MASK; + /* If there are a lot of unused frames, + * restock the Rx queue so ucode wont assert. */ + if (fill_rx) { + count++; + if (count >= 8) { + priv->rxq.read = i; + __iwl_rx_replenish(priv); + count = 0; + } + } + } + + /* Backtrack one entry */ + priv->rxq.read = i; + iwl_rx_queue_restock(priv); +} + +#ifdef CONFIG_IWLWIFI_DEBUG +static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) +{ + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; + DECLARE_MAC_BUF(mac); + + IWL_DEBUG_RADIO("RX CONFIG:\n"); + iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); + IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); + IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); + IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n", + le32_to_cpu(rxon->filter_flags)); + IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type); + IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", + rxon->ofdm_basic_rates); + IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); + IWL_DEBUG_RADIO("u8[6] node_addr: %s\n", + print_mac(mac, rxon->node_addr)); + IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n", + print_mac(mac, rxon->bssid_addr)); + IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); +} +#endif + +static void iwl4965_enable_interrupts(struct iwl_priv *priv) +{ + IWL_DEBUG_ISR("Enabling interrupts\n"); + set_bit(STATUS_INT_ENABLED, &priv->status); + iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); +} + +/* call this function to flush any scheduled tasklet */ +static inline void iwl_synchronize_irq(struct iwl_priv *priv) +{ + /* wait to make sure we flush pedding tasklet*/ + synchronize_irq(priv->pci_dev->irq); + tasklet_kill(&priv->irq_tasklet); +} + +static inline void iwl4965_disable_interrupts(struct iwl_priv *priv) +{ + clear_bit(STATUS_INT_ENABLED, &priv->status); + + /* disable interrupts from uCode/NIC to host */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + /* acknowledge/clear/reset any interrupts still pending + * from uCode or flow handler (Rx/Tx DMA) */ + iwl_write32(priv, CSR_INT, 0xffffffff); + iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); + IWL_DEBUG_ISR("Disabled interrupts\n"); +} + + +/** + * iwl4965_irq_handle_error - called for HW or SW error interrupt from card + */ +static void iwl4965_irq_handle_error(struct iwl_priv *priv) +{ + /* Set the FW error flag -- cleared on iwl4965_down */ + set_bit(STATUS_FW_ERROR, &priv->status); + + /* Cancel currently queued command. */ + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (priv->debug_level & IWL_DL_FW_ERRORS) { + iwl_dump_nic_error_log(priv); + iwl_dump_nic_event_log(priv); + iwl4965_print_rx_config_cmd(priv); + } +#endif + + wake_up_interruptible(&priv->wait_command_queue); + + /* Keep the restart process from trying to send host + * commands by clearing the INIT status bit */ + clear_bit(STATUS_READY, &priv->status); + + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { + IWL_DEBUG(IWL_DL_FW_ERRORS, + "Restarting adapter due to uCode error.\n"); + + if (iwl_is_associated(priv)) { + memcpy(&priv->recovery_rxon, &priv->active_rxon, + sizeof(priv->recovery_rxon)); + priv->error_recovering = 1; + } + if (priv->cfg->mod_params->restart_fw) + queue_work(priv->workqueue, &priv->restart); + } +} + +static void iwl4965_error_recovery(struct iwl_priv *priv) +{ + unsigned long flags; + + memcpy(&priv->staging_rxon, &priv->recovery_rxon, + sizeof(priv->staging_rxon)); + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl4965_commit_rxon(priv); + + iwl_rxon_add_station(priv, priv->bssid, 1); + + spin_lock_irqsave(&priv->lock, flags); + priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); + priv->error_recovering = 0; + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void iwl4965_irq_tasklet(struct iwl_priv *priv) +{ + u32 inta, handled = 0; + u32 inta_fh; + unsigned long flags; +#ifdef CONFIG_IWLWIFI_DEBUG + u32 inta_mask; +#endif + + spin_lock_irqsave(&priv->lock, flags); + + /* Ack/clear/reset pending uCode interrupts. + * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, + * and will clear only when CSR_FH_INT_STATUS gets cleared. */ + inta = iwl_read32(priv, CSR_INT); + iwl_write32(priv, CSR_INT, inta); + + /* Ack/clear/reset pending flow-handler (DMA) interrupts. + * Any new interrupts that happen after this, either while we're + * in this tasklet, or later, will show up in next ISR/tasklet. */ + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); + iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (priv->debug_level & IWL_DL_ISR) { + /* just for debug */ + inta_mask = iwl_read32(priv, CSR_INT_MASK); + IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", + inta, inta_mask, inta_fh); + } +#endif + + /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not + * atomic, make sure that inta covers all the interrupts that + * we've discovered, even if FH interrupt came in just after + * reading CSR_INT. */ + if (inta_fh & CSR49_FH_INT_RX_MASK) + inta |= CSR_INT_BIT_FH_RX; + if (inta_fh & CSR49_FH_INT_TX_MASK) + inta |= CSR_INT_BIT_FH_TX; + + /* Now service all interrupt bits discovered above. */ + if (inta & CSR_INT_BIT_HW_ERR) { + IWL_ERROR("Microcode HW error detected. Restarting.\n"); + + /* Tell the device to stop sending interrupts */ + iwl4965_disable_interrupts(priv); + + iwl4965_irq_handle_error(priv); + + handled |= CSR_INT_BIT_HW_ERR; + + spin_unlock_irqrestore(&priv->lock, flags); + + return; + } + +#ifdef CONFIG_IWLWIFI_DEBUG + if (priv->debug_level & (IWL_DL_ISR)) { + /* NIC fires this, but we don't use it, redundant with WAKEUP */ + if (inta & CSR_INT_BIT_SCD) + IWL_DEBUG_ISR("Scheduler finished to transmit " + "the frame/frames.\n"); + + /* Alive notification via Rx interrupt will do the real work */ + if (inta & CSR_INT_BIT_ALIVE) + IWL_DEBUG_ISR("Alive interrupt\n"); + } +#endif + /* Safely ignore these bits for debug checks below */ + inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); + + /* HW RF KILL switch toggled */ + if (inta & CSR_INT_BIT_RF_KILL) { + int hw_rf_kill = 0; + if (!(iwl_read32(priv, CSR_GP_CNTRL) & + CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) + hw_rf_kill = 1; + + IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n", + hw_rf_kill ? "disable radio":"enable radio"); + + /* driver only loads ucode once setting the interface up. + * the driver as well won't allow loading if RFKILL is set + * therefore no need to restart the driver from this handler + */ + if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) + clear_bit(STATUS_RF_KILL_HW, &priv->status); + + handled |= CSR_INT_BIT_RF_KILL; + } + + /* Chip got too hot and stopped itself */ + if (inta & CSR_INT_BIT_CT_KILL) { + IWL_ERROR("Microcode CT kill error detected.\n"); + handled |= CSR_INT_BIT_CT_KILL; + } + + /* Error detected by uCode */ + if (inta & CSR_INT_BIT_SW_ERR) { + IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n", + inta); + iwl4965_irq_handle_error(priv); + handled |= CSR_INT_BIT_SW_ERR; + } + + /* uCode wakes up after power-down sleep */ + if (inta & CSR_INT_BIT_WAKEUP) { + IWL_DEBUG_ISR("Wakeup interrupt\n"); + iwl_rx_queue_update_write_ptr(priv, &priv->rxq); + iwl_txq_update_write_ptr(priv, &priv->txq[0]); + iwl_txq_update_write_ptr(priv, &priv->txq[1]); + iwl_txq_update_write_ptr(priv, &priv->txq[2]); + iwl_txq_update_write_ptr(priv, &priv->txq[3]); + iwl_txq_update_write_ptr(priv, &priv->txq[4]); + iwl_txq_update_write_ptr(priv, &priv->txq[5]); + + handled |= CSR_INT_BIT_WAKEUP; + } + + /* All uCode command responses, including Tx command responses, + * Rx "responses" (frame-received notification), and other + * notifications from uCode come through here*/ + if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { + iwl_rx_handle(priv); + handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); + } + + if (inta & CSR_INT_BIT_FH_TX) { + IWL_DEBUG_ISR("Tx interrupt\n"); + handled |= CSR_INT_BIT_FH_TX; + /* FH finished to write, send event */ + priv->ucode_write_complete = 1; + wake_up_interruptible(&priv->wait_command_queue); + } + + if (inta & ~handled) + IWL_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); + + if (inta & ~CSR_INI_SET_MASK) { + IWL_WARNING("Disabled INTA bits 0x%08x were pending\n", + inta & ~CSR_INI_SET_MASK); + IWL_WARNING(" with FH_INT = 0x%08x\n", inta_fh); + } + + /* Re-enable all interrupts */ + /* only Re-enable if diabled by irq */ + if (test_bit(STATUS_INT_ENABLED, &priv->status)) + iwl4965_enable_interrupts(priv); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (priv->debug_level & (IWL_DL_ISR)) { + inta = iwl_read32(priv, CSR_INT); + inta_mask = iwl_read32(priv, CSR_INT_MASK); + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); + IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, " + "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); + } +#endif + spin_unlock_irqrestore(&priv->lock, flags); +} + +static irqreturn_t iwl4965_isr(int irq, void *data) +{ + struct iwl_priv *priv = data; + u32 inta, inta_mask; + u32 inta_fh; + if (!priv) + return IRQ_NONE; + + spin_lock(&priv->lock); + + /* Disable (but don't clear!) interrupts here to avoid + * back-to-back ISRs and sporadic interrupts from our NIC. + * If we have something to service, the tasklet will re-enable ints. + * If we *don't* have something, we'll re-enable before leaving here. */ + inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + /* Discover which interrupts are active/pending */ + inta = iwl_read32(priv, CSR_INT); + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); + + /* Ignore interrupt if there's nothing in NIC to service. + * This may be due to IRQ shared with another device, + * or due to sporadic interrupts thrown from our NIC. */ + if (!inta && !inta_fh) { + IWL_DEBUG_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n"); + goto none; + } + + if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { + /* Hardware disappeared. It might have already raised + * an interrupt */ + IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta); + goto unplugged; + } + + IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", + inta, inta_mask, inta_fh); + + inta &= ~CSR_INT_BIT_SCD; + + /* iwl4965_irq_tasklet() will service interrupts and re-enable them */ + if (likely(inta || inta_fh)) + tasklet_schedule(&priv->irq_tasklet); + + unplugged: + spin_unlock(&priv->lock); + return IRQ_HANDLED; + + none: + /* re-enable interrupts here since we don't have anything to service. */ + /* only Re-enable if diabled by irq */ + if (test_bit(STATUS_INT_ENABLED, &priv->status)) + iwl4965_enable_interrupts(priv); + spin_unlock(&priv->lock); + return IRQ_NONE; +} + +/****************************************************************************** + * + * uCode download functions + * + ******************************************************************************/ + +static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv) +{ + iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); + iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); + iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup); + iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init); + iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data); + iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); +} + +static void iwl4965_nic_start(struct iwl_priv *priv) +{ + /* Remove all resets to allow NIC to operate */ + iwl_write32(priv, CSR_RESET, 0); +} + + +/** + * iwl4965_read_ucode - Read uCode images from disk file. + * + * Copy into buffers for card to fetch via bus-mastering + */ +static int iwl4965_read_ucode(struct iwl_priv *priv) +{ + struct iwl_ucode *ucode; + int ret; + const struct firmware *ucode_raw; + const char *name = priv->cfg->fw_name; + u8 *src; + size_t len; + u32 ver, inst_size, data_size, init_size, init_data_size, boot_size; + + /* Ask kernel firmware_class module to get the boot firmware off disk. + * request_firmware() is synchronous, file is in memory on return. */ + ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev); + if (ret < 0) { + IWL_ERROR("%s firmware file req failed: Reason %d\n", + name, ret); + goto error; + } + + IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", + name, ucode_raw->size); + + /* Make sure that we got at least our header! */ + if (ucode_raw->size < sizeof(*ucode)) { + IWL_ERROR("File size way too small!\n"); + ret = -EINVAL; + goto err_release; + } + + /* Data from ucode file: header followed by uCode images */ + ucode = (void *)ucode_raw->data; + + ver = le32_to_cpu(ucode->ver); + inst_size = le32_to_cpu(ucode->inst_size); + data_size = le32_to_cpu(ucode->data_size); + init_size = le32_to_cpu(ucode->init_size); + init_data_size = le32_to_cpu(ucode->init_data_size); + boot_size = le32_to_cpu(ucode->boot_size); + + IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver); + IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", + inst_size); + IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", + data_size); + IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n", + init_size); + IWL_DEBUG_INFO("f/w package hdr init data size = %u\n", + init_data_size); + IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n", + boot_size); + + /* Verify size of file vs. image size info in file's header */ + if (ucode_raw->size < sizeof(*ucode) + + inst_size + data_size + init_size + + init_data_size + boot_size) { + + IWL_DEBUG_INFO("uCode file size %d too small\n", + (int)ucode_raw->size); + ret = -EINVAL; + goto err_release; + } + + /* Verify that uCode images will fit in card's SRAM */ + if (inst_size > priv->hw_params.max_inst_size) { + IWL_DEBUG_INFO("uCode instr len %d too large to fit in\n", + inst_size); + ret = -EINVAL; + goto err_release; + } + + if (data_size > priv->hw_params.max_data_size) { + IWL_DEBUG_INFO("uCode data len %d too large to fit in\n", + data_size); + ret = -EINVAL; + goto err_release; + } + if (init_size > priv->hw_params.max_inst_size) { + IWL_DEBUG_INFO + ("uCode init instr len %d too large to fit in\n", + init_size); + ret = -EINVAL; + goto err_release; + } + if (init_data_size > priv->hw_params.max_data_size) { + IWL_DEBUG_INFO + ("uCode init data len %d too large to fit in\n", + init_data_size); + ret = -EINVAL; + goto err_release; + } + if (boot_size > priv->hw_params.max_bsm_size) { + IWL_DEBUG_INFO + ("uCode boot instr len %d too large to fit in\n", + boot_size); + ret = -EINVAL; + goto err_release; + } + + /* Allocate ucode buffers for card's bus-master loading ... */ + + /* Runtime instructions and 2 copies of data: + * 1) unmodified from disk + * 2) backup cache for save/restore during power-downs */ + priv->ucode_code.len = inst_size; + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code); + + priv->ucode_data.len = data_size; + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data); + + priv->ucode_data_backup.len = data_size; + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup); + + /* Initialization instructions and data */ + if (init_size && init_data_size) { + priv->ucode_init.len = init_size; + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init); + + priv->ucode_init_data.len = init_data_size; + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data); + + if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr) + goto err_pci_alloc; + } + + /* Bootstrap (instructions only, no data) */ + if (boot_size) { + priv->ucode_boot.len = boot_size; + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot); + + if (!priv->ucode_boot.v_addr) + goto err_pci_alloc; + } + + /* Copy images into buffers for card's bus-master reads ... */ + + /* Runtime instructions (first block of data in file) */ + src = &ucode->data[0]; + len = priv->ucode_code.len; + IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %Zd\n", len); + memcpy(priv->ucode_code.v_addr, src, len); + IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", + priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); + + /* Runtime data (2nd block) + * NOTE: Copy into backup buffer will be done in iwl4965_up() */ + src = &ucode->data[inst_size]; + len = priv->ucode_data.len; + IWL_DEBUG_INFO("Copying (but not loading) uCode data len %Zd\n", len); + memcpy(priv->ucode_data.v_addr, src, len); + memcpy(priv->ucode_data_backup.v_addr, src, len); + + /* Initialization instructions (3rd block) */ + if (init_size) { + src = &ucode->data[inst_size + data_size]; + len = priv->ucode_init.len; + IWL_DEBUG_INFO("Copying (but not loading) init instr len %Zd\n", + len); + memcpy(priv->ucode_init.v_addr, src, len); + } + + /* Initialization data (4th block) */ + if (init_data_size) { + src = &ucode->data[inst_size + data_size + init_size]; + len = priv->ucode_init_data.len; + IWL_DEBUG_INFO("Copying (but not loading) init data len %Zd\n", + len); + memcpy(priv->ucode_init_data.v_addr, src, len); + } + + /* Bootstrap instructions (5th block) */ + src = &ucode->data[inst_size + data_size + init_size + init_data_size]; + len = priv->ucode_boot.len; + IWL_DEBUG_INFO("Copying (but not loading) boot instr len %Zd\n", len); + memcpy(priv->ucode_boot.v_addr, src, len); + + /* We have our copies now, allow OS release its copies */ + release_firmware(ucode_raw); + return 0; + + err_pci_alloc: + IWL_ERROR("failed to allocate pci memory\n"); + ret = -ENOMEM; + iwl4965_dealloc_ucode_pci(priv); + + err_release: + release_firmware(ucode_raw); + + error: + return ret; +} + +/** + * iwl_alive_start - called after REPLY_ALIVE notification received + * from protocol/runtime uCode (initialization uCode's + * Alive gets handled by iwl_init_alive_start()). + */ +static void iwl_alive_start(struct iwl_priv *priv) +{ + int ret = 0; + + IWL_DEBUG_INFO("Runtime Alive received.\n"); + + if (priv->card_alive.is_valid != UCODE_VALID_OK) { + /* We had an error bringing up the hardware, so take it + * all the way back down so we can try again */ + IWL_DEBUG_INFO("Alive failed.\n"); + goto restart; + } + + /* Initialize uCode has loaded Runtime uCode ... verify inst image. + * This is a paranoid check, because we would not have gotten the + * "runtime" alive if code weren't properly loaded. */ + if (iwl_verify_ucode(priv)) { + /* Runtime instruction load was bad; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Bad runtime uCode load.\n"); + goto restart; + } + + iwl_clear_stations_table(priv); + ret = priv->cfg->ops->lib->alive_notify(priv); + if (ret) { + IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n", + ret); + goto restart; + } + + /* After the ALIVE response, we can send host commands to 4965 uCode */ + set_bit(STATUS_ALIVE, &priv->status); + + if (iwl_is_rfkill(priv)) + return; + + ieee80211_wake_queues(priv->hw); + + priv->active_rate = priv->rates_mask; + priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; + + if (iwl_is_associated(priv)) { + struct iwl_rxon_cmd *active_rxon = + (struct iwl_rxon_cmd *)&priv->active_rxon; + + memcpy(&priv->staging_rxon, &priv->active_rxon, + sizeof(priv->staging_rxon)); + active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; + } else { + /* Initialize our rx_config data */ + iwl4965_connection_init_rx_config(priv); + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); + } + + /* Configure Bluetooth device coexistence support */ + iwl4965_send_bt_config(priv); + + iwl_reset_run_time_calib(priv); + + /* Configure the adapter for unassociated operation */ + iwl4965_commit_rxon(priv); + + /* At this point, the NIC is initialized and operational */ + iwl_rf_kill_ct_config(priv); + + iwl_leds_register(priv); + + IWL_DEBUG_INFO("ALIVE processing complete.\n"); + set_bit(STATUS_READY, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); + + if (priv->error_recovering) + iwl4965_error_recovery(priv); + + iwl_power_update_mode(priv, 1); + ieee80211_notify_mac(priv->hw, IEEE80211_NOTIFY_RE_ASSOC); + + if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status)) + iwl4965_set_mode(priv, priv->iw_mode); + + return; + + restart: + queue_work(priv->workqueue, &priv->restart); +} + +static void iwl_cancel_deferred_work(struct iwl_priv *priv); + +static void __iwl4965_down(struct iwl_priv *priv) +{ + unsigned long flags; + int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); + + IWL_DEBUG_INFO(DRV_NAME " is going down\n"); + + if (!exit_pending) + set_bit(STATUS_EXIT_PENDING, &priv->status); + + iwl_leds_unregister(priv); + + iwl_clear_stations_table(priv); + + /* Unblock any waiting calls */ + wake_up_interruptible_all(&priv->wait_command_queue); + + /* Wipe out the EXIT_PENDING status bit if we are not actually + * exiting the module */ + if (!exit_pending) + clear_bit(STATUS_EXIT_PENDING, &priv->status); + + /* stop and reset the on-board processor */ + iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); + + /* tell the device to stop sending interrupts */ + spin_lock_irqsave(&priv->lock, flags); + iwl4965_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + iwl_synchronize_irq(priv); + + if (priv->mac80211_registered) + ieee80211_stop_queues(priv->hw); + + /* If we have not previously called iwl4965_init() then + * clear all bits but the RF Kill and SUSPEND bits and return */ + if (!iwl_is_init(priv)) { + priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << + STATUS_RF_KILL_HW | + test_bit(STATUS_RF_KILL_SW, &priv->status) << + STATUS_RF_KILL_SW | + test_bit(STATUS_GEO_CONFIGURED, &priv->status) << + STATUS_GEO_CONFIGURED | + test_bit(STATUS_IN_SUSPEND, &priv->status) << + STATUS_IN_SUSPEND | + test_bit(STATUS_EXIT_PENDING, &priv->status) << + STATUS_EXIT_PENDING; + goto exit; + } + + /* ...otherwise clear out all the status bits but the RF Kill and + * SUSPEND bits and continue taking the NIC down. */ + priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << + STATUS_RF_KILL_HW | + test_bit(STATUS_RF_KILL_SW, &priv->status) << + STATUS_RF_KILL_SW | + test_bit(STATUS_GEO_CONFIGURED, &priv->status) << + STATUS_GEO_CONFIGURED | + test_bit(STATUS_IN_SUSPEND, &priv->status) << + STATUS_IN_SUSPEND | + test_bit(STATUS_FW_ERROR, &priv->status) << + STATUS_FW_ERROR | + test_bit(STATUS_EXIT_PENDING, &priv->status) << + STATUS_EXIT_PENDING; + + spin_lock_irqsave(&priv->lock, flags); + iwl_clear_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_txq_ctx_stop(priv); + iwl_rxq_stop(priv); + + spin_lock_irqsave(&priv->lock, flags); + if (!iwl_grab_nic_access(priv)) { + iwl_write_prph(priv, APMG_CLK_DIS_REG, + APMG_CLK_VAL_DMA_CLK_RQT); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->lock, flags); + + udelay(5); + + /* FIXME: apm_ops.suspend(priv) */ + priv->cfg->ops->lib->apm_ops.reset(priv); + priv->cfg->ops->lib->free_shared_mem(priv); + + exit: + memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); + + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + priv->ibss_beacon = NULL; + + /* clear out any free frames */ + iwl_clear_free_frames(priv); +} + +static void iwl4965_down(struct iwl_priv *priv) +{ + mutex_lock(&priv->mutex); + __iwl4965_down(priv); + mutex_unlock(&priv->mutex); + + iwl_cancel_deferred_work(priv); +} + +#define MAX_HW_RESTARTS 5 + +static int __iwl4965_up(struct iwl_priv *priv) +{ + int i; + int ret; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + IWL_WARNING("Exit pending; will not bring the NIC up\n"); + return -EIO; + } + + if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { + IWL_ERROR("ucode not available for device bringup\n"); + return -EIO; + } + + /* If platform's RF_KILL switch is NOT set to KILL */ + if (iwl_read32(priv, CSR_GP_CNTRL) & + CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) + clear_bit(STATUS_RF_KILL_HW, &priv->status); + else + set_bit(STATUS_RF_KILL_HW, &priv->status); + + if (!test_bit(STATUS_IN_SUSPEND, &priv->status) && + iwl_is_rfkill(priv)) { + IWL_WARNING("Radio disabled by %s RF Kill switch\n", + test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW"); + return -ENODEV; + } + + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + + ret = priv->cfg->ops->lib->alloc_shared_mem(priv); + if (ret) { + IWL_ERROR("Unable to allocate shared memory\n"); + return ret; + } + + ret = iwl_hw_nic_init(priv); + if (ret) { + IWL_ERROR("Unable to init nic\n"); + return ret; + } + + /* make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + + /* clear (again), then enable host interrupts */ + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl4965_enable_interrupts(priv); + + /* really make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + /* Copy original ucode data image from disk into backup cache. + * This will be used to initialize the on-board processor's + * data SRAM for a clean start when the runtime program first loads. */ + memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, + priv->ucode_data.len); + + /* We return success when we resume from suspend and rf_kill is on. */ + if (test_bit(STATUS_RF_KILL_HW, &priv->status) || + test_bit(STATUS_RF_KILL_SW, &priv->status)) + return 0; + + for (i = 0; i < MAX_HW_RESTARTS; i++) { + + iwl_clear_stations_table(priv); + + /* load bootstrap state machine, + * load bootstrap program into processor's memory, + * prepare to load the "initialize" uCode */ + ret = priv->cfg->ops->lib->load_ucode(priv); + + if (ret) { + IWL_ERROR("Unable to set up bootstrap uCode: %d\n", ret); + continue; + } + + /* Clear out the uCode error bit if it is set */ + clear_bit(STATUS_FW_ERROR, &priv->status); + + /* start card; "initialize" will load runtime ucode */ + iwl4965_nic_start(priv); + + IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); + + return 0; + } + + set_bit(STATUS_EXIT_PENDING, &priv->status); + __iwl4965_down(priv); + clear_bit(STATUS_EXIT_PENDING, &priv->status); + + /* tried to restart and config the device for as long as our + * patience could withstand */ + IWL_ERROR("Unable to initialize device after %d attempts.\n", i); + return -EIO; +} + + +/***************************************************************************** + * + * Workqueue callbacks + * + *****************************************************************************/ + +static void iwl_bg_init_alive_start(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, init_alive_start.work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + priv->cfg->ops->lib->init_alive_start(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_alive_start(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, alive_start.work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl_alive_start(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl4965_bg_rf_kill(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); + + wake_up_interruptible(&priv->wait_command_queue); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + + if (!iwl_is_rfkill(priv)) { + IWL_DEBUG(IWL_DL_RF_KILL, + "HW and/or SW RF Kill no longer active, restarting " + "device\n"); + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) + queue_work(priv->workqueue, &priv->restart); + } else { + /* make sure mac80211 stop sending Tx frame */ + if (priv->mac80211_registered) + ieee80211_stop_queues(priv->hw); + + if (!test_bit(STATUS_RF_KILL_HW, &priv->status)) + IWL_DEBUG_RF_KILL("Can not turn radio back on - " + "disabled by SW switch\n"); + else + IWL_WARNING("Radio Frequency Kill Switch is On:\n" + "Kill switch must be turned off for " + "wireless networking to work.\n"); + } + mutex_unlock(&priv->mutex); + iwl_rfkill_set_hw_state(priv); +} + +static void iwl4965_bg_set_monitor(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, + struct iwl_priv, set_monitor); + int ret; + + IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n"); + + mutex_lock(&priv->mutex); + + ret = iwl4965_set_mode(priv, IEEE80211_IF_TYPE_MNTR); + + if (ret) { + if (ret == -EAGAIN) + IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n"); + else + IWL_ERROR("iwl4965_set_mode() failed ret = %d\n", ret); + } + + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_run_time_calib_work(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, + run_time_calib_work); + + mutex_lock(&priv->mutex); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + test_bit(STATUS_SCANNING, &priv->status)) { + mutex_unlock(&priv->mutex); + return; + } + + if (priv->start_calib) { + iwl_chain_noise_calibration(priv, &priv->statistics); + + iwl_sensitivity_calibration(priv, &priv->statistics); + } + + mutex_unlock(&priv->mutex); + return; +} + +static void iwl4965_bg_up(struct work_struct *data) +{ + struct iwl_priv *priv = container_of(data, struct iwl_priv, up); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + __iwl4965_up(priv); + mutex_unlock(&priv->mutex); + iwl_rfkill_set_hw_state(priv); +} + +static void iwl4965_bg_restart(struct work_struct *data) +{ + struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + iwl4965_down(priv); + queue_work(priv->workqueue, &priv->up); +} + +static void iwl4965_bg_rx_replenish(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, rx_replenish); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl_rx_replenish(priv); + mutex_unlock(&priv->mutex); +} + +#define IWL_DELAY_NEXT_SCAN (HZ*2) + +static void iwl4965_post_associate(struct iwl_priv *priv) +{ + struct ieee80211_conf *conf = NULL; + int ret = 0; + DECLARE_MAC_BUF(mac); + unsigned long flags; + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__); + return; + } + + IWL_DEBUG_ASSOC("Associated as %d to: %s\n", + priv->assoc_id, + print_mac(mac, priv->active_rxon.bssid_addr)); + + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + + if (!priv->vif || !priv->is_open) + return; + + iwl_scan_cancel_timeout(priv, 200); + + conf = ieee80211_get_hw_conf(priv->hw); + + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl4965_commit_rxon(priv); + + memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd)); + iwl4965_setup_rxon_timing(priv); + ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, + sizeof(priv->rxon_timing), &priv->rxon_timing); + if (ret) + IWL_WARNING("REPLY_RXON_TIMING failed - " + "Attempting to continue.\n"); + + priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; + + if (priv->current_ht_config.is_ht) + iwl_set_rxon_ht(priv, &priv->current_ht_config); + + iwl_set_rxon_chain(priv); + priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); + + IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n", + priv->assoc_id, priv->beacon_int); + + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) + priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + } + + iwl4965_commit_rxon(priv); + + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_STA: + break; + + case IEEE80211_IF_TYPE_IBSS: + + /* assume default assoc id */ + priv->assoc_id = 1; + + iwl_rxon_add_station(priv, priv->bssid, 0); + iwl4965_send_beacon_cmd(priv); + + break; + + default: + IWL_ERROR("%s Should not be called in %d mode\n", + __FUNCTION__, priv->iw_mode); + break; + } + + /* Enable Rx differential gain and sensitivity calibrations */ + iwl_chain_noise_reset(priv); + priv->start_calib = 1; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->assoc_station_added = 1; + + spin_lock_irqsave(&priv->lock, flags); + iwl_activate_qos(priv, 0); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_power_update_mode(priv, 0); + /* we have just associated, don't start scan too early */ + priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; +} + +static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); + +static void iwl_bg_scan_completed(struct work_struct *work) +{ + struct iwl_priv *priv = + container_of(work, struct iwl_priv, scan_completed); + + IWL_DEBUG_SCAN("SCAN complete scan\n"); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + if (test_bit(STATUS_CONF_PENDING, &priv->status)) + iwl4965_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw)); + + ieee80211_scan_completed(priv->hw); + + /* Since setting the TXPOWER may have been deferred while + * performing the scan, fire one off */ + mutex_lock(&priv->mutex); + iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); + mutex_unlock(&priv->mutex); +} + +/***************************************************************************** + * + * mac80211 entry point functions + * + *****************************************************************************/ + +#define UCODE_READY_TIMEOUT (4 * HZ) + +static int iwl4965_mac_start(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + int ret; + + IWL_DEBUG_MAC80211("enter\n"); + + if (pci_enable_device(priv->pci_dev)) { + IWL_ERROR("Fail to pci_enable_device\n"); + return -ENODEV; + } + pci_restore_state(priv->pci_dev); + pci_enable_msi(priv->pci_dev); + + ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED, + DRV_NAME, priv); + if (ret) { + IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq); + goto out_disable_msi; + } + + /* we should be verifying the device is ready to be opened */ + mutex_lock(&priv->mutex); + + memset(&priv->staging_rxon, 0, sizeof(struct iwl_rxon_cmd)); + /* fetch ucode file from disk, alloc and copy to bus-master buffers ... + * ucode filename and max sizes are card-specific. */ + + if (!priv->ucode_code.len) { + ret = iwl4965_read_ucode(priv); + if (ret) { + IWL_ERROR("Could not read microcode: %d\n", ret); + mutex_unlock(&priv->mutex); + goto out_release_irq; + } + } + + ret = __iwl4965_up(priv); + + mutex_unlock(&priv->mutex); + + iwl_rfkill_set_hw_state(priv); + + if (ret) + goto out_release_irq; + + IWL_DEBUG_INFO("Start UP work done.\n"); + + if (test_bit(STATUS_IN_SUSPEND, &priv->status)) + return 0; + + /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from + * mac80211 will not be run successfully. */ + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + test_bit(STATUS_READY, &priv->status), + UCODE_READY_TIMEOUT); + if (!ret) { + if (!test_bit(STATUS_READY, &priv->status)) { + IWL_ERROR("START_ALIVE timeout after %dms.\n", + jiffies_to_msecs(UCODE_READY_TIMEOUT)); + ret = -ETIMEDOUT; + goto out_release_irq; + } + } + + priv->is_open = 1; + IWL_DEBUG_MAC80211("leave\n"); + return 0; + +out_release_irq: + free_irq(priv->pci_dev->irq, priv); +out_disable_msi: + pci_disable_msi(priv->pci_dev); + pci_disable_device(priv->pci_dev); + priv->is_open = 0; + IWL_DEBUG_MAC80211("leave - failed\n"); + return ret; +} + +static void iwl4965_mac_stop(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + if (!priv->is_open) { + IWL_DEBUG_MAC80211("leave - skip\n"); + return; + } + + priv->is_open = 0; + + if (iwl_is_ready_rf(priv)) { + /* stop mac, cancel any scan request and clear + * RXON_FILTER_ASSOC_MSK BIT + */ + mutex_lock(&priv->mutex); + iwl_scan_cancel_timeout(priv, 100); + mutex_unlock(&priv->mutex); + } + + iwl4965_down(priv); + + flush_workqueue(priv->workqueue); + free_irq(priv->pci_dev->irq, priv); + pci_disable_msi(priv->pci_dev); + pci_save_state(priv->pci_dev); + pci_disable_device(priv->pci_dev); + + IWL_DEBUG_MAC80211("leave\n"); +} + +static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { + IWL_DEBUG_MAC80211("leave - monitor\n"); + dev_kfree_skb_any(skb); + return 0; + } + + IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, + ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); + + if (iwl_tx_skb(priv, skb)) + dev_kfree_skb_any(skb); + + IWL_DEBUG_MAC80211("leave\n"); + return 0; +} + +static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + DECLARE_MAC_BUF(mac); + + IWL_DEBUG_MAC80211("enter: type %d\n", conf->type); + + if (priv->vif) { + IWL_DEBUG_MAC80211("leave - vif != NULL\n"); + return -EOPNOTSUPP; + } + + spin_lock_irqsave(&priv->lock, flags); + priv->vif = conf->vif; + + spin_unlock_irqrestore(&priv->lock, flags); + + mutex_lock(&priv->mutex); + + if (conf->mac_addr) { + IWL_DEBUG_MAC80211("Set %s\n", print_mac(mac, conf->mac_addr)); + memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); + } + + if (iwl4965_set_mode(priv, conf->type) == -EAGAIN) + /* we are not ready, will run again when ready */ + set_bit(STATUS_MODE_PENDING, &priv->status); + + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211("leave\n"); + return 0; +} + +/** + * iwl4965_mac_config - mac80211 config callback + * + * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to + * be set inappropriately and the driver currently sets the hardware up to + * use it whenever needed. + */ +static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + const struct iwl_channel_info *ch_info; + unsigned long flags; + int ret = 0; + u16 channel; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); + + priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP); + + if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) { + IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n"); + goto out; + } + + if (!conf->radio_enabled) + iwl_radio_kill_sw_disable_radio(priv); + + if (!iwl_is_ready(priv)) { + IWL_DEBUG_MAC80211("leave - not ready\n"); + ret = -EIO; + goto out; + } + + if (unlikely(!priv->cfg->mod_params->disable_hw_scan && + test_bit(STATUS_SCANNING, &priv->status))) { + IWL_DEBUG_MAC80211("leave - scanning\n"); + set_bit(STATUS_CONF_PENDING, &priv->status); + mutex_unlock(&priv->mutex); + return 0; + } + + channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + ch_info = iwl_get_channel_info(priv, conf->channel->band, channel); + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_MAC80211("leave - invalid channel\n"); + ret = -EINVAL; + goto out; + } + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS && + !is_channel_ibss(ch_info)) { + IWL_ERROR("channel %d in band %d not IBSS channel\n", + conf->channel->hw_value, conf->channel->band); + ret = -EINVAL; + goto out; + } + + spin_lock_irqsave(&priv->lock, flags); + + + /* if we are switching from ht to 2.4 clear flags + * from any ht related info since 2.4 does not + * support ht */ + if ((le16_to_cpu(priv->staging_rxon.channel) != channel) +#ifdef IEEE80211_CONF_CHANNEL_SWITCH + && !(conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) +#endif + ) + priv->staging_rxon.flags = 0; + + iwl_set_rxon_channel(priv, conf->channel->band, channel); + + iwl_set_flags_for_band(priv, conf->channel->band); + + /* The list of supported rates and rate mask can be different + * for each band; since the band may have changed, reset + * the rate mask to what mac80211 lists */ + iwl4965_set_rate(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + +#ifdef IEEE80211_CONF_CHANNEL_SWITCH + if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) { + iwl4965_hw_channel_switch(priv, conf->channel); + goto out; + } +#endif + + if (!conf->radio_enabled) { + IWL_DEBUG_MAC80211("leave - radio disabled\n"); + goto out; + } + + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_MAC80211("leave - RF kill\n"); + ret = -EIO; + goto out; + } + + IWL_DEBUG_MAC80211("TX Power old=%d new=%d\n", + priv->tx_power_user_lmt, conf->power_level); + + iwl_set_tx_power(priv, conf->power_level, false); + + iwl4965_set_rate(priv); + + if (memcmp(&priv->active_rxon, + &priv->staging_rxon, sizeof(priv->staging_rxon))) + iwl4965_commit_rxon(priv); + else + IWL_DEBUG_INFO("No re-sending same RXON configuration.\n"); + + IWL_DEBUG_MAC80211("leave\n"); + +out: + clear_bit(STATUS_CONF_PENDING, &priv->status); + mutex_unlock(&priv->mutex); + return ret; +} + +static void iwl4965_config_ap(struct iwl_priv *priv) +{ + int ret = 0; + unsigned long flags; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + /* The following should be done only at AP bring up */ + if (!(iwl_is_associated(priv))) { + + /* RXON - unassoc (to set timing command) */ + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl4965_commit_rxon(priv); + + /* RXON Timing */ + memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd)); + iwl4965_setup_rxon_timing(priv); + ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, + sizeof(priv->rxon_timing), &priv->rxon_timing); + if (ret) + IWL_WARNING("REPLY_RXON_TIMING failed - " + "Attempting to continue.\n"); + + iwl_set_rxon_chain(priv); + + /* FIXME: what should be the assoc_id for AP? */ + priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + priv->staging_rxon.flags |= + RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags &= + ~RXON_FLG_SHORT_PREAMBLE_MSK; + + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { + if (priv->assoc_capability & + WLAN_CAPABILITY_SHORT_SLOT_TIME) + priv->staging_rxon.flags |= + RXON_FLG_SHORT_SLOT_MSK; + else + priv->staging_rxon.flags &= + ~RXON_FLG_SHORT_SLOT_MSK; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->staging_rxon.flags &= + ~RXON_FLG_SHORT_SLOT_MSK; + } + /* restore RXON assoc */ + priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; + iwl4965_commit_rxon(priv); + spin_lock_irqsave(&priv->lock, flags); + iwl_activate_qos(priv, 1); + spin_unlock_irqrestore(&priv->lock, flags); + iwl_rxon_add_station(priv, iwl_bcast_addr, 0); + } + iwl4965_send_beacon_cmd(priv); + + /* FIXME - we need to add code here to detect a totally new + * configuration, reset the AP, unassoc, rxon timing, assoc, + * clear sta table, add BCAST sta... */ +} + +/* temporary */ +static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); + +static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + DECLARE_MAC_BUF(mac); + unsigned long flags; + int rc; + + if (conf == NULL) + return -EIO; + + if (priv->vif != vif) { + IWL_DEBUG_MAC80211("leave - priv->vif != vif\n"); + return 0; + } + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS && + conf->changed & IEEE80211_IFCC_BEACON) { + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + if (!beacon) + return -ENOMEM; + rc = iwl4965_mac_beacon_update(hw, beacon); + if (rc) + return rc; + } + + if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + (!conf->ssid_len)) { + IWL_DEBUG_MAC80211 + ("Leaving in AP mode because HostAPD is not ready.\n"); + return 0; + } + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + mutex_lock(&priv->mutex); + + if (conf->bssid) + IWL_DEBUG_MAC80211("bssid: %s\n", + print_mac(mac, conf->bssid)); + +/* + * very dubious code was here; the probe filtering flag is never set: + * + if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && + !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { + */ + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (!conf->bssid) { + conf->bssid = priv->mac_addr; + memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); + IWL_DEBUG_MAC80211("bssid was set to: %s\n", + print_mac(mac, conf->bssid)); + } + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = ieee80211_beacon_get(hw, vif); + } + + if (iwl_is_rfkill(priv)) + goto done; + + if (conf->bssid && !is_zero_ether_addr(conf->bssid) && + !is_multicast_ether_addr(conf->bssid)) { + /* If there is currently a HW scan going on in the background + * then we need to cancel it else the RXON below will fail. */ + if (iwl_scan_cancel_timeout(priv, 100)) { + IWL_WARNING("Aborted scan still in progress " + "after 100ms\n"); + IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); + mutex_unlock(&priv->mutex); + return -EAGAIN; + } + memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN); + + /* TODO: Audit driver for usage of these members and see + * if mac80211 deprecates them (priv->bssid looks like it + * shouldn't be there, but I haven't scanned the IBSS code + * to verify) - jpk */ + memcpy(priv->bssid, conf->bssid, ETH_ALEN); + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + iwl4965_config_ap(priv); + else { + rc = iwl4965_commit_rxon(priv); + if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc) + iwl_rxon_add_station( + priv, priv->active_rxon.bssid_addr, 1); + } + + } else { + iwl_scan_cancel_timeout(priv, 100); + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl4965_commit_rxon(priv); + } + + done: + spin_lock_irqsave(&priv->lock, flags); + if (!conf->ssid_len) + memset(priv->essid, 0, IW_ESSID_MAX_SIZE); + else + memcpy(priv->essid, conf->ssid, conf->ssid_len); + + priv->essid_len = conf->ssid_len; + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_MAC80211("leave\n"); + mutex_unlock(&priv->mutex); + + return 0; +} + +static void iwl4965_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mc_list) +{ + struct iwl_priv *priv = hw->priv; + + if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { + IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", + IEEE80211_IF_TYPE_MNTR, + changed_flags, *total_flags); + /* queue work 'cuz mac80211 is holding a lock which + * prevents us from issuing (synchronous) f/w cmds */ + queue_work(priv->workqueue, &priv->set_monitor); + } + *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | + FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; +} + +static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + mutex_lock(&priv->mutex); + + if (iwl_is_ready_rf(priv)) { + iwl_scan_cancel_timeout(priv, 100); + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl4965_commit_rxon(priv); + } + if (priv->vif == conf->vif) { + priv->vif = NULL; + memset(priv->bssid, 0, ETH_ALEN); + memset(priv->essid, 0, IW_ESSID_MAX_SIZE); + priv->essid_len = 0; + } + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211("leave\n"); + +} + +#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) +static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("changes = 0x%X\n", changes); + + if (changes & BSS_CHANGED_ERP_PREAMBLE) { + IWL_DEBUG_MAC80211("ERP_PREAMBLE %d\n", + bss_conf->use_short_preamble); + if (bss_conf->use_short_preamble) + priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + } + + if (changes & BSS_CHANGED_ERP_CTS_PROT) { + IWL_DEBUG_MAC80211("ERP_CTS %d\n", bss_conf->use_cts_prot); + if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ)) + priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK; + } + + if (changes & BSS_CHANGED_HT) { + IWL_DEBUG_MAC80211("HT %d\n", bss_conf->assoc_ht); + iwl4965_ht_conf(priv, bss_conf); + iwl_set_rxon_chain(priv); + } + + if (changes & BSS_CHANGED_ASSOC) { + IWL_DEBUG_MAC80211("ASSOC %d\n", bss_conf->assoc); + /* This should never happen as this function should + * never be called from interrupt context. */ + if (WARN_ON_ONCE(in_interrupt())) + return; + if (bss_conf->assoc) { + priv->assoc_id = bss_conf->aid; + priv->beacon_int = bss_conf->beacon_int; + priv->power_data.dtim_period = bss_conf->dtim_period; + priv->timestamp = bss_conf->timestamp; + priv->assoc_capability = bss_conf->assoc_capability; + priv->next_scan_jiffies = jiffies + + IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; + mutex_lock(&priv->mutex); + iwl4965_post_associate(priv); + mutex_unlock(&priv->mutex); + } else { + priv->assoc_id = 0; + IWL_DEBUG_MAC80211("DISASSOC %d\n", bss_conf->assoc); + } + } else if (changes && iwl_is_associated(priv) && priv->assoc_id) { + IWL_DEBUG_MAC80211("Associated Changes %d\n", changes); + iwl_send_rxon_assoc(priv); + } + +} + +static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) +{ + int rc = 0; + unsigned long flags; + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + mutex_lock(&priv->mutex); + spin_lock_irqsave(&priv->lock, flags); + + if (!iwl_is_ready_rf(priv)) { + rc = -EIO; + IWL_DEBUG_MAC80211("leave - not ready or exit pending\n"); + goto out_unlock; + } + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */ + rc = -EIO; + IWL_ERROR("ERROR: APs don't scan\n"); + goto out_unlock; + } + + /* we don't schedule scan within next_scan_jiffies period */ + if (priv->next_scan_jiffies && + time_after(priv->next_scan_jiffies, jiffies)) { + rc = -EAGAIN; + goto out_unlock; + } + /* if we just finished scan ask for delay */ + if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies + + IWL_DELAY_NEXT_SCAN, jiffies)) { + rc = -EAGAIN; + goto out_unlock; + } + if (len) { + IWL_DEBUG_SCAN("direct scan for %s [%d]\n ", + iwl_escape_essid(ssid, len), (int)len); + + priv->one_direct_scan = 1; + priv->direct_ssid_len = (u8) + min((u8) len, (u8) IW_ESSID_MAX_SIZE); + memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); + } else + priv->one_direct_scan = 0; + + rc = iwl_scan_initiate(priv); + + IWL_DEBUG_MAC80211("leave\n"); + +out_unlock: + spin_unlock_irqrestore(&priv->lock, flags); + mutex_unlock(&priv->mutex); + + return rc; +} + +static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw, + struct ieee80211_key_conf *keyconf, const u8 *addr, + u32 iv32, u16 *phase1key) +{ + struct iwl_priv *priv = hw->priv; + u8 sta_id = IWL_INVALID_STATION; + unsigned long flags; + __le16 key_flags = 0; + int i; + DECLARE_MAC_BUF(mac); + + IWL_DEBUG_MAC80211("enter\n"); + + sta_id = iwl_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_MAC80211("leave - %s not in station map.\n", + print_mac(mac, addr)); + return; + } + + iwl_scan_cancel_timeout(priv, 100); + + key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK); + key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); + key_flags &= ~STA_KEY_FLG_INVALID; + + if (sta_id == priv->hw_params.bcast_sta_id) + key_flags |= STA_KEY_MULTICAST_MSK; + + spin_lock_irqsave(&priv->sta_lock, flags); + + priv->stations[sta_id].sta.key.key_flags = key_flags; + priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32; + + for (i = 0; i < 5; i++) + priv->stations[sta_id].sta.key.tkip_rx_ttak[i] = + cpu_to_le16(phase1key[i]); + + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + + spin_unlock_irqrestore(&priv->sta_lock, flags); + + IWL_DEBUG_MAC80211("leave\n"); +} + +static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + const u8 *local_addr, const u8 *addr, + struct ieee80211_key_conf *key) +{ + struct iwl_priv *priv = hw->priv; + DECLARE_MAC_BUF(mac); + int ret = 0; + u8 sta_id = IWL_INVALID_STATION; + u8 is_default_wep_key = 0; + + IWL_DEBUG_MAC80211("enter\n"); + + if (priv->hw_params.sw_crypto) { + IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n"); + return -EOPNOTSUPP; + } + + if (is_zero_ether_addr(addr)) + /* only support pairwise keys */ + return -EOPNOTSUPP; + + sta_id = iwl_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_MAC80211("leave - %s not in station map.\n", + print_mac(mac, addr)); + return -EINVAL; + + } + + mutex_lock(&priv->mutex); + iwl_scan_cancel_timeout(priv, 100); + mutex_unlock(&priv->mutex); + + /* If we are getting WEP group key and we didn't receive any key mapping + * so far, we are in legacy wep mode (group key only), otherwise we are + * in 1X mode. + * In legacy wep mode, we use another host command to the uCode */ + if (key->alg == ALG_WEP && sta_id == priv->hw_params.bcast_sta_id && + priv->iw_mode != IEEE80211_IF_TYPE_AP) { + if (cmd == SET_KEY) + is_default_wep_key = !priv->key_mapping_key; + else + is_default_wep_key = + (key->hw_key_idx == HW_KEY_DEFAULT); + } + + switch (cmd) { + case SET_KEY: + if (is_default_wep_key) + ret = iwl_set_default_wep_key(priv, key); + else + ret = iwl_set_dynamic_key(priv, key, sta_id); + + IWL_DEBUG_MAC80211("enable hwcrypto key\n"); + break; + case DISABLE_KEY: + if (is_default_wep_key) + ret = iwl_remove_default_wep_key(priv, key); + else + ret = iwl_remove_dynamic_key(priv, key, sta_id); + + IWL_DEBUG_MAC80211("disable hwcrypto key\n"); + break; + default: + ret = -EINVAL; + } + + IWL_DEBUG_MAC80211("leave\n"); + + return ret; +} + +static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + int q; + + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - RF not ready\n"); + return -EIO; + } + + if (queue >= AC_NUM) { + IWL_DEBUG_MAC80211("leave - queue >= AC_NUM %d\n", queue); + return 0; + } + + if (!priv->qos_data.qos_enable) { + priv->qos_data.qos_active = 0; + IWL_DEBUG_MAC80211("leave - qos not enabled\n"); + return 0; + } + q = AC_NUM - 1 - queue; + + spin_lock_irqsave(&priv->lock, flags); + + priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min); + priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); + priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; + priv->qos_data.def_qos_parm.ac[q].edca_txop = + cpu_to_le16((params->txop * 32)); + + priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; + priv->qos_data.qos_active = 1; + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + iwl_activate_qos(priv, 1); + else if (priv->assoc_id && iwl_is_associated(priv)) + iwl_activate_qos(priv, 0); + + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_MAC80211("leave\n"); + return 0; +} + +static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, + enum ieee80211_ampdu_mlme_action action, + const u8 *addr, u16 tid, u16 *ssn) +{ + struct iwl_priv *priv = hw->priv; + DECLARE_MAC_BUF(mac); + + IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n", + print_mac(mac, addr), tid); + + if (!(priv->cfg->sku & IWL_SKU_N)) + return -EACCES; + + switch (action) { + case IEEE80211_AMPDU_RX_START: + IWL_DEBUG_HT("start Rx\n"); + return iwl_rx_agg_start(priv, addr, tid, *ssn); + case IEEE80211_AMPDU_RX_STOP: + IWL_DEBUG_HT("stop Rx\n"); + return iwl_rx_agg_stop(priv, addr, tid); + case IEEE80211_AMPDU_TX_START: + IWL_DEBUG_HT("start Tx\n"); + return iwl_tx_agg_start(priv, addr, tid, ssn); + case IEEE80211_AMPDU_TX_STOP: + IWL_DEBUG_HT("stop Tx\n"); + return iwl_tx_agg_stop(priv, addr, tid); + default: + IWL_DEBUG_HT("unknown\n"); + return -EINVAL; + break; + } + return 0; +} +static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct iwl_priv *priv = hw->priv; + int i, avail; + struct iwl_tx_queue *txq; + struct iwl_queue *q; + unsigned long flags; + + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - RF not ready\n"); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); + + for (i = 0; i < AC_NUM; i++) { + txq = &priv->txq[i]; + q = &txq->q; + avail = iwl_queue_space(q); + + stats[i].len = q->n_window - avail; + stats[i].limit = q->n_window - q->high_mark; + stats[i].count = q->n_window; + + } + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static int iwl4965_mac_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + struct iwl_priv *priv = hw->priv; + + priv = hw->priv; + IWL_DEBUG_MAC80211("enter\n"); + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211("enter\n"); + + spin_lock_irqsave(&priv->lock, flags); + memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info)); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_reset_qos(priv); + + spin_lock_irqsave(&priv->lock, flags); + priv->assoc_id = 0; + priv->assoc_capability = 0; + priv->assoc_station_added = 0; + + /* new association get rid of ibss beacon skb */ + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = NULL; + + priv->beacon_int = priv->hw->conf.beacon_int; + priv->timestamp = 0; + if ((priv->iw_mode == IEEE80211_IF_TYPE_STA)) + priv->beacon_int = 0; + + spin_unlock_irqrestore(&priv->lock, flags); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - not ready\n"); + mutex_unlock(&priv->mutex); + return; + } + + /* we are restarting association process + * clear RXON_FILTER_ASSOC_MSK bit + */ + if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { + iwl_scan_cancel_timeout(priv, 100); + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl4965_commit_rxon(priv); + } + + iwl_power_update_mode(priv, 0); + + /* Per mac80211.h: This is only used in IBSS mode... */ + if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + + IWL_DEBUG_MAC80211("leave - not in IBSS\n"); + mutex_unlock(&priv->mutex); + return; + } + + iwl4965_set_rate(priv); + + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211("leave\n"); +} + +static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + __le64 timestamp; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - RF not ready\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + IWL_DEBUG_MAC80211("leave - not IBSS\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = skb; + + priv->assoc_id = 0; + timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; + priv->timestamp = le64_to_cpu(timestamp) + (priv->beacon_int * 1000); + + IWL_DEBUG_MAC80211("leave\n"); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_reset_qos(priv); + + iwl4965_post_associate(priv); + + mutex_unlock(&priv->mutex); + + return 0; +} + +/***************************************************************************** + * + * sysfs attributes + * + *****************************************************************************/ + +#ifdef CONFIG_IWLWIFI_DEBUG + +/* + * The following adds a new attribute to the sysfs representation + * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/) + * used for controlling the debug level. + * + * See the level definitions in iwl for details. + */ + +static ssize_t show_debug_level(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = d->driver_data; + + return sprintf(buf, "0x%08X\n", priv->debug_level); +} +static ssize_t store_debug_level(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = d->driver_data; + char *p = (char *)buf; + u32 val; + + val = simple_strtoul(p, &p, 0); + if (p == buf) + printk(KERN_INFO DRV_NAME + ": %s is not in hex or decimal form.\n", buf); + else + priv->debug_level = val; + + return strnlen(buf, count); +} + +static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, + show_debug_level, store_debug_level); + + +#endif /* CONFIG_IWLWIFI_DEBUG */ + + +static ssize_t show_version(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = d->driver_data; + struct iwl_alive_resp *palive = &priv->card_alive; + ssize_t pos = 0; + u16 eeprom_ver; + + if (palive->is_valid) + pos += sprintf(buf + pos, + "fw version: 0x%01X.0x%01X.0x%01X.0x%01X\n" + "fw type: 0x%01X 0x%01X\n", + palive->ucode_major, palive->ucode_minor, + palive->sw_rev[0], palive->sw_rev[1], + palive->ver_type, palive->ver_subtype); + else + pos += sprintf(buf + pos, "fw not loaded\n"); + + if (priv->eeprom) { + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); + pos += sprintf(buf + pos, "EEPROM version: 0x%x\n", + eeprom_ver); + } else { + pos += sprintf(buf + pos, "EEPROM not initialzed\n"); + } + + return pos; +} + +static DEVICE_ATTR(version, S_IWUSR | S_IRUGO, show_version, NULL); + +static ssize_t show_temperature(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + return sprintf(buf, "%d\n", priv->temperature); +} + +static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); + +static ssize_t show_tx_power(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + return sprintf(buf, "%d\n", priv->tx_power_user_lmt); +} + +static ssize_t store_tx_power(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + char *p = (char *)buf; + u32 val; + + val = simple_strtoul(p, &p, 10); + if (p == buf) + printk(KERN_INFO DRV_NAME + ": %s is not in decimal form.\n", buf); + else + iwl_set_tx_power(priv, val, false); + + return count; +} + +static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); + +static ssize_t show_flags(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + return sprintf(buf, "0x%04X\n", priv->active_rxon.flags); +} + +static ssize_t store_flags(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + u32 flags = simple_strtoul(buf, NULL, 0); + + mutex_lock(&priv->mutex); + if (le32_to_cpu(priv->staging_rxon.flags) != flags) { + /* Cancel any currently running scans... */ + if (iwl_scan_cancel_timeout(priv, 100)) + IWL_WARNING("Could not cancel scan.\n"); + else { + IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n", + flags); + priv->staging_rxon.flags = cpu_to_le32(flags); + iwl4965_commit_rxon(priv); + } + } + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags); + +static ssize_t show_filter_flags(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + return sprintf(buf, "0x%04X\n", + le32_to_cpu(priv->active_rxon.filter_flags)); +} + +static ssize_t store_filter_flags(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + u32 filter_flags = simple_strtoul(buf, NULL, 0); + + mutex_lock(&priv->mutex); + if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) { + /* Cancel any currently running scans... */ + if (iwl_scan_cancel_timeout(priv, 100)) + IWL_WARNING("Could not cancel scan.\n"); + else { + IWL_DEBUG_INFO("Committing rxon.filter_flags = " + "0x%04X\n", filter_flags); + priv->staging_rxon.filter_flags = + cpu_to_le32(filter_flags); + iwl4965_commit_rxon(priv); + } + } + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, + store_filter_flags); + +#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT + +static ssize_t show_measurement(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + struct iwl4965_spectrum_notification measure_report; + u32 size = sizeof(measure_report), len = 0, ofs = 0; + u8 *data = (u8 *) & measure_report; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (!(priv->measurement_status & MEASUREMENT_READY)) { + spin_unlock_irqrestore(&priv->lock, flags); + return 0; + } + memcpy(&measure_report, &priv->measure_report, size); + priv->measurement_status = 0; + spin_unlock_irqrestore(&priv->lock, flags); + + while (size && (PAGE_SIZE - len)) { + hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, + PAGE_SIZE - len, 1); + len = strlen(buf); + if (PAGE_SIZE - len) + buf[len++] = '\n'; + + ofs += 16; + size -= min(size, 16U); + } + + return len; +} + +static ssize_t store_measurement(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + struct ieee80211_measurement_params params = { + .channel = le16_to_cpu(priv->active_rxon.channel), + .start_time = cpu_to_le64(priv->last_tsf), + .duration = cpu_to_le16(1), + }; + u8 type = IWL_MEASURE_BASIC; + u8 buffer[32]; + u8 channel; + + if (count) { + char *p = buffer; + strncpy(buffer, buf, min(sizeof(buffer), count)); + channel = simple_strtoul(p, NULL, 0); + if (channel) + params.channel = channel; + + p = buffer; + while (*p && *p != ' ') + p++; + if (*p) + type = simple_strtoul(p + 1, NULL, 0); + } + + IWL_DEBUG_INFO("Invoking measurement of type %d on " + "channel %d (for '%s')\n", type, params.channel, buf); + iwl4965_get_measurement(priv, ¶ms, type); + + return count; +} + +static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, + show_measurement, store_measurement); +#endif /* CONFIG_IWL4965_SPECTRUM_MEASUREMENT */ + +static ssize_t store_retry_rate(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + + priv->retry_rate = simple_strtoul(buf, NULL, 0); + if (priv->retry_rate <= 0) + priv->retry_rate = 1; + + return count; +} + +static ssize_t show_retry_rate(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "%d", priv->retry_rate); +} + +static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate, + store_retry_rate); + +static ssize_t store_power_level(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + int ret; + int mode; + + mode = simple_strtoul(buf, NULL, 0); + mutex_lock(&priv->mutex); + + if (!iwl_is_ready(priv)) { + ret = -EAGAIN; + goto out; + } + + ret = iwl_power_set_user_mode(priv, mode); + if (ret) { + IWL_DEBUG_MAC80211("failed setting power mode.\n"); + goto out; + } + ret = count; + + out: + mutex_unlock(&priv->mutex); + return ret; +} + +static ssize_t show_power_level(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + int mode = priv->power_data.user_power_setting; + int system = priv->power_data.system_power_setting; + int level = priv->power_data.power_mode; + char *p = buf; + + switch (system) { + case IWL_POWER_SYS_AUTO: + p += sprintf(p, "SYSTEM:auto"); + break; + case IWL_POWER_SYS_AC: + p += sprintf(p, "SYSTEM:ac"); + break; + case IWL_POWER_SYS_BATTERY: + p += sprintf(p, "SYSTEM:battery"); + break; + } + + p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO)?"fixed":"auto"); + p += sprintf(p, "\tINDEX:%d", level); + p += sprintf(p, "\n"); + return (p - buf + 1); +} + +static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, + store_power_level); + +static ssize_t show_channels(struct device *d, + struct device_attribute *attr, char *buf) +{ + + struct iwl_priv *priv = dev_get_drvdata(d); + struct ieee80211_channel *channels = NULL; + const struct ieee80211_supported_band *supp_band = NULL; + int len = 0, i; + int count = 0; + + if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status)) + return -EAGAIN; + + supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ); + channels = supp_band->channels; + count = supp_band->n_channels; + + len += sprintf(&buf[len], + "Displaying %d channels in 2.4GHz band " + "(802.11bg):\n", count); + + for (i = 0; i < count; i++) + len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", + ieee80211_frequency_to_channel( + channels[i].center_freq), + channels[i].max_power, + channels[i].flags & IEEE80211_CHAN_RADAR ? + " (IEEE 802.11h required)" : "", + (!(channels[i].flags & IEEE80211_CHAN_NO_IBSS) + || (channels[i].flags & + IEEE80211_CHAN_RADAR)) ? "" : + ", IBSS", + channels[i].flags & + IEEE80211_CHAN_PASSIVE_SCAN ? + "passive only" : "active/passive"); + + supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ); + channels = supp_band->channels; + count = supp_band->n_channels; + + len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band " + "(802.11a):\n", count); + + for (i = 0; i < count; i++) + len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", + ieee80211_frequency_to_channel( + channels[i].center_freq), + channels[i].max_power, + channels[i].flags & IEEE80211_CHAN_RADAR ? + " (IEEE 802.11h required)" : "", + ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) + || (channels[i].flags & + IEEE80211_CHAN_RADAR)) ? "" : + ", IBSS", + channels[i].flags & + IEEE80211_CHAN_PASSIVE_SCAN ? + "passive only" : "active/passive"); + + return len; +} + +static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); + +static ssize_t show_statistics(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + u32 size = sizeof(struct iwl_notif_statistics); + u32 len = 0, ofs = 0; + u8 *data = (u8 *) & priv->statistics; + int rc = 0; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + mutex_lock(&priv->mutex); + rc = iwl_send_statistics_request(priv, 0); + mutex_unlock(&priv->mutex); + + if (rc) { + len = sprintf(buf, + "Error sending statistics request: 0x%08X\n", rc); + return len; + } + + while (size && (PAGE_SIZE - len)) { + hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, + PAGE_SIZE - len, 1); + len = strlen(buf); + if (PAGE_SIZE - len) + buf[len++] = '\n'; + + ofs += 16; + size -= min(size, 16U); + } + + return len; +} + +static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL); + +static ssize_t show_status(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + if (!iwl_is_alive(priv)) + return -EAGAIN; + return sprintf(buf, "0x%08x\n", (int)priv->status); +} + +static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); + +/***************************************************************************** + * + * driver setup and teardown + * + *****************************************************************************/ + +static void iwl_setup_deferred_work(struct iwl_priv *priv) +{ + priv->workqueue = create_workqueue(DRV_NAME); + + init_waitqueue_head(&priv->wait_command_queue); + + INIT_WORK(&priv->up, iwl4965_bg_up); + INIT_WORK(&priv->restart, iwl4965_bg_restart); + INIT_WORK(&priv->rx_replenish, iwl4965_bg_rx_replenish); + INIT_WORK(&priv->rf_kill, iwl4965_bg_rf_kill); + INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update); + INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor); + INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); + INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); + INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); + + /* FIXME : remove when resolved PENDING */ + INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); + iwl_setup_scan_deferred_work(priv); + + if (priv->cfg->ops->lib->setup_deferred_work) + priv->cfg->ops->lib->setup_deferred_work(priv); + + init_timer(&priv->statistics_periodic); + priv->statistics_periodic.data = (unsigned long)priv; + priv->statistics_periodic.function = iwl4965_bg_statistics_periodic; + + tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) + iwl4965_irq_tasklet, (unsigned long)priv); +} + +static void iwl_cancel_deferred_work(struct iwl_priv *priv) +{ + if (priv->cfg->ops->lib->cancel_deferred_work) + priv->cfg->ops->lib->cancel_deferred_work(priv); + + cancel_delayed_work_sync(&priv->init_alive_start); + cancel_delayed_work(&priv->scan_check); + cancel_delayed_work(&priv->alive_start); + cancel_work_sync(&priv->beacon_update); + del_timer_sync(&priv->statistics_periodic); +} + +static struct attribute *iwl4965_sysfs_entries[] = { + &dev_attr_channels.attr, + &dev_attr_flags.attr, + &dev_attr_filter_flags.attr, +#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT + &dev_attr_measurement.attr, +#endif + &dev_attr_power_level.attr, + &dev_attr_retry_rate.attr, + &dev_attr_statistics.attr, + &dev_attr_status.attr, + &dev_attr_temperature.attr, + &dev_attr_tx_power.attr, +#ifdef CONFIG_IWLWIFI_DEBUG + &dev_attr_debug_level.attr, +#endif + &dev_attr_version.attr, + + NULL +}; + +static struct attribute_group iwl4965_attribute_group = { + .name = NULL, /* put in device directory */ + .attrs = iwl4965_sysfs_entries, +}; + +static struct ieee80211_ops iwl4965_hw_ops = { + .tx = iwl4965_mac_tx, + .start = iwl4965_mac_start, + .stop = iwl4965_mac_stop, + .add_interface = iwl4965_mac_add_interface, + .remove_interface = iwl4965_mac_remove_interface, + .config = iwl4965_mac_config, + .config_interface = iwl4965_mac_config_interface, + .configure_filter = iwl4965_configure_filter, + .set_key = iwl4965_mac_set_key, + .update_tkip_key = iwl4965_mac_update_tkip_key, + .get_stats = iwl4965_mac_get_stats, + .get_tx_stats = iwl4965_mac_get_tx_stats, + .conf_tx = iwl4965_mac_conf_tx, + .reset_tsf = iwl4965_mac_reset_tsf, + .bss_info_changed = iwl4965_bss_info_changed, + .ampdu_action = iwl4965_mac_ampdu_action, + .hw_scan = iwl4965_mac_hw_scan +}; + +static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int err = 0; + struct iwl_priv *priv; + struct ieee80211_hw *hw; + struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); + unsigned long flags; + DECLARE_MAC_BUF(mac); + + /************************ + * 1. Allocating HW data + ************************/ + + /* Disabling hardware scan means that mac80211 will perform scans + * "the hard way", rather than using device's scan. */ + if (cfg->mod_params->disable_hw_scan) { + if (cfg->mod_params->debug & IWL_DL_INFO) + dev_printk(KERN_DEBUG, &(pdev->dev), + "Disabling hw_scan\n"); + iwl4965_hw_ops.hw_scan = NULL; + } + + hw = iwl_alloc_all(cfg, &iwl4965_hw_ops); + if (!hw) { + err = -ENOMEM; + goto out; + } + priv = hw->priv; + /* At this point both hw and priv are allocated. */ + + SET_IEEE80211_DEV(hw, &pdev->dev); + + IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); + priv->cfg = cfg; + priv->pci_dev = pdev; + +#ifdef CONFIG_IWLWIFI_DEBUG + priv->debug_level = priv->cfg->mod_params->debug; + atomic_set(&priv->restrict_refcnt, 0); +#endif + + /************************** + * 2. Initializing PCI bus + **************************/ + if (pci_enable_device(pdev)) { + err = -ENODEV; + goto out_ieee80211_free_hw; + } + + pci_set_master(pdev); + + err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + if (!err) + err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (err) { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (!err) + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + /* both attempts failed: */ + if (err) { + printk(KERN_WARNING "%s: No suitable DMA available.\n", + DRV_NAME); + goto out_pci_disable_device; + } + } + + err = pci_request_regions(pdev, DRV_NAME); + if (err) + goto out_pci_disable_device; + + pci_set_drvdata(pdev, priv); + + /* We disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_write_config_byte(pdev, 0x41, 0x00); + + /*********************** + * 3. Read REV register + ***********************/ + priv->hw_base = pci_iomap(pdev, 0, 0); + if (!priv->hw_base) { + err = -ENODEV; + goto out_pci_release_regions; + } + + IWL_DEBUG_INFO("pci_resource_len = 0x%08llx\n", + (unsigned long long) pci_resource_len(pdev, 0)); + IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base); + + iwl_hw_detect(priv); + printk(KERN_INFO DRV_NAME + ": Detected Intel Wireless WiFi Link %s REV=0x%X\n", + priv->cfg->name, priv->hw_rev); + + /* amp init */ + err = priv->cfg->ops->lib->apm_ops.init(priv); + if (err < 0) { + IWL_DEBUG_INFO("Failed to init APMG\n"); + goto out_iounmap; + } + /***************** + * 4. Read EEPROM + *****************/ + /* Read the EEPROM */ + err = iwl_eeprom_init(priv); + if (err) { + IWL_ERROR("Unable to init EEPROM\n"); + goto out_iounmap; + } + err = iwl_eeprom_check_version(priv); + if (err) + goto out_iounmap; + + /* extract MAC Address */ + iwl_eeprom_get_mac(priv, priv->mac_addr); + IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr)); + SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); + + /************************ + * 5. Setup HW constants + ************************/ + if (iwl_set_hw_params(priv)) { + IWL_ERROR("failed to set hw parameters\n"); + goto out_free_eeprom; + } + + /******************* + * 6. Setup priv + *******************/ + + err = iwl_init_drv(priv); + if (err) + goto out_free_eeprom; + /* At this point both hw and priv are initialized. */ + + /********************************** + * 7. Initialize module parameters + **********************************/ + + /* Disable radio (SW RF KILL) via parameter when loading driver */ + if (priv->cfg->mod_params->disable) { + set_bit(STATUS_RF_KILL_SW, &priv->status); + IWL_DEBUG_INFO("Radio disabled.\n"); + } + + /******************** + * 8. Setup services + ********************/ + spin_lock_irqsave(&priv->lock, flags); + iwl4965_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group); + if (err) { + IWL_ERROR("failed to create sysfs device attributes\n"); + goto out_uninit_drv; + } + + + iwl_setup_deferred_work(priv); + iwl_setup_rx_handlers(priv); + + /******************** + * 9. Conclude + ********************/ + pci_save_state(pdev); + pci_disable_device(pdev); + + /********************************** + * 10. Setup and register mac80211 + **********************************/ + + err = iwl_setup_mac(priv); + if (err) + goto out_remove_sysfs; + + err = iwl_dbgfs_register(priv, DRV_NAME); + if (err) + IWL_ERROR("failed to create debugfs files\n"); + + err = iwl_rfkill_init(priv); + if (err) + IWL_ERROR("Unable to initialize RFKILL system. " + "Ignoring error: %d\n", err); + iwl_power_initialize(priv); + return 0; + + out_remove_sysfs: + sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); + out_uninit_drv: + iwl_uninit_drv(priv); + out_free_eeprom: + iwl_eeprom_free(priv); + out_iounmap: + pci_iounmap(pdev, priv->hw_base); + out_pci_release_regions: + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); + out_pci_disable_device: + pci_disable_device(pdev); + out_ieee80211_free_hw: + ieee80211_free_hw(priv->hw); + out: + return err; +} + +static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + unsigned long flags; + + if (!priv) + return; + + IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n"); + + iwl_dbgfs_unregister(priv); + sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); + + if (priv->mac80211_registered) { + ieee80211_unregister_hw(priv->hw); + priv->mac80211_registered = 0; + } + + set_bit(STATUS_EXIT_PENDING, &priv->status); + + iwl4965_down(priv); + + /* make sure we flush any pending irq or + * tasklet for the driver + */ + spin_lock_irqsave(&priv->lock, flags); + iwl4965_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_synchronize_irq(priv); + + iwl_rfkill_unregister(priv); + iwl4965_dealloc_ucode_pci(priv); + + if (priv->rxq.bd) + iwl_rx_queue_free(priv, &priv->rxq); + iwl_hw_txq_ctx_free(priv); + + iwl_clear_stations_table(priv); + iwl_eeprom_free(priv); + + + /*netif_stop_queue(dev); */ + flush_workqueue(priv->workqueue); + + /* ieee80211_unregister_hw calls iwl4965_mac_stop, which flushes + * priv->workqueue... so we can't take down the workqueue + * until now... */ + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; + + pci_iounmap(pdev, priv->hw_base); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + + iwl_uninit_drv(priv); + + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + ieee80211_free_hw(priv->hw); +} + +#ifdef CONFIG_PM + +static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + + if (priv->is_open) { + set_bit(STATUS_IN_SUSPEND, &priv->status); + iwl4965_mac_stop(priv->hw); + priv->is_open = 1; + } + + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int iwl4965_pci_resume(struct pci_dev *pdev) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + + pci_set_power_state(pdev, PCI_D0); + + if (priv->is_open) + iwl4965_mac_start(priv->hw); + + clear_bit(STATUS_IN_SUSPEND, &priv->status); + return 0; +} + +#endif /* CONFIG_PM */ + +/***************************************************************************** + * + * driver and module entry point + * + *****************************************************************************/ + +/* Hardware specific file defines the PCI IDs table for that hardware module */ +static struct pci_device_id iwl_hw_card_ids[] = { + {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)}, + {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)}, +#ifdef CONFIG_IWL5000 + {IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bg_cfg)}, + {IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bg_cfg)}, + {IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)}, + {IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)}, + {IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)}, + {IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)}, + {IWL_PCI_DEVICE(0x4232, PCI_ANY_ID, iwl5100_agn_cfg)}, + {IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)}, + {IWL_PCI_DEVICE(0x4236, PCI_ANY_ID, iwl5300_agn_cfg)}, + {IWL_PCI_DEVICE(0x4237, PCI_ANY_ID, iwl5100_agn_cfg)}, + {IWL_PCI_DEVICE(0x423A, PCI_ANY_ID, iwl5350_agn_cfg)}, +#endif /* CONFIG_IWL5000 */ + {0} +}; +MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); + +static struct pci_driver iwl_driver = { + .name = DRV_NAME, + .id_table = iwl_hw_card_ids, + .probe = iwl4965_pci_probe, + .remove = __devexit_p(iwl4965_pci_remove), +#ifdef CONFIG_PM + .suspend = iwl4965_pci_suspend, + .resume = iwl4965_pci_resume, +#endif +}; + +static int __init iwl4965_init(void) +{ + + int ret; + printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); + printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); + + ret = iwlagn_rate_control_register(); + if (ret) { + IWL_ERROR("Unable to register rate control algorithm: %d\n", ret); + return ret; + } + + ret = pci_register_driver(&iwl_driver); + if (ret) { + IWL_ERROR("Unable to initialize PCI module\n"); + goto error_register; + } + + return ret; + +error_register: + iwlagn_rate_control_unregister(); + return ret; +} + +static void __exit iwl4965_exit(void) +{ + pci_unregister_driver(&iwl_driver); + iwlagn_rate_control_unregister(); +} + +module_exit(iwl4965_exit); +module_init(iwl4965_init); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c deleted file mode 100644 index f71b3f3f81b..00000000000 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ /dev/null @@ -1,4523 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * James P. Ketrenos - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "iwl-eeprom.h" -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-io.h" -#include "iwl-helpers.h" -#include "iwl-sta.h" -#include "iwl-calib.h" - - -/****************************************************************************** - * - * module boiler plate - * - ******************************************************************************/ - -/* - * module name, copyright, version, etc. - * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk - */ - -#define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link AGN driver for Linux" - -#ifdef CONFIG_IWLWIFI_DEBUG -#define VD "d" -#else -#define VD -#endif - -#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT -#define VS "s" -#else -#define VS -#endif - -#define DRV_VERSION IWLWIFI_VERSION VD VS - - -MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_VERSION(DRV_VERSION); -MODULE_AUTHOR(DRV_COPYRIGHT); -MODULE_LICENSE("GPL"); - -/*************** STATION TABLE MANAGEMENT **** - * mac80211 should be examined to determine if sta_info is duplicating - * the functionality provided here - */ - -/**************************************************************/ - - - -static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) -{ - struct iwl_rxon_cmd *rxon = &priv->staging_rxon; - - if (hw_decrypt) - rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; - else - rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK; - -} - -/** - * iwl4965_check_rxon_cmd - validate RXON structure is valid - * - * NOTE: This is really only useful during development and can eventually - * be #ifdef'd out once the driver is stable and folks aren't actively - * making changes - */ -static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon) -{ - int error = 0; - int counter = 1; - - if (rxon->flags & RXON_FLG_BAND_24G_MSK) { - error |= le32_to_cpu(rxon->flags & - (RXON_FLG_TGJ_NARROW_BAND_MSK | - RXON_FLG_RADAR_DETECT_MSK)); - if (error) - IWL_WARNING("check 24G fields %d | %d\n", - counter++, error); - } else { - error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ? - 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK); - if (error) - IWL_WARNING("check 52 fields %d | %d\n", - counter++, error); - error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK); - if (error) - IWL_WARNING("check 52 CCK %d | %d\n", - counter++, error); - } - error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1; - if (error) - IWL_WARNING("check mac addr %d | %d\n", counter++, error); - - /* make sure basic rates 6Mbps and 1Mbps are supported */ - error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) && - ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0)); - if (error) - IWL_WARNING("check basic rate %d | %d\n", counter++, error); - - error |= (le16_to_cpu(rxon->assoc_id) > 2007); - if (error) - IWL_WARNING("check assoc id %d | %d\n", counter++, error); - - error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) - == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)); - if (error) - IWL_WARNING("check CCK and short slot %d | %d\n", - counter++, error); - - error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) - == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)); - if (error) - IWL_WARNING("check CCK & auto detect %d | %d\n", - counter++, error); - - error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | - RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK); - if (error) - IWL_WARNING("check TGG and auto detect %d | %d\n", - counter++, error); - - if (error) - IWL_WARNING("Tuning to channel %d\n", - le16_to_cpu(rxon->channel)); - - if (error) { - IWL_ERROR("Not a valid iwl4965_rxon_assoc_cmd field values\n"); - return -1; - } - return 0; -} - -/** - * iwl4965_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed - * @priv: staging_rxon is compared to active_rxon - * - * If the RXON structure is changing enough to require a new tune, - * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that - * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required. - */ -static int iwl4965_full_rxon_required(struct iwl_priv *priv) -{ - - /* These items are only settable from the full RXON command */ - if (!(iwl_is_associated(priv)) || - compare_ether_addr(priv->staging_rxon.bssid_addr, - priv->active_rxon.bssid_addr) || - compare_ether_addr(priv->staging_rxon.node_addr, - priv->active_rxon.node_addr) || - compare_ether_addr(priv->staging_rxon.wlap_bssid_addr, - priv->active_rxon.wlap_bssid_addr) || - (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) || - (priv->staging_rxon.channel != priv->active_rxon.channel) || - (priv->staging_rxon.air_propagation != - priv->active_rxon.air_propagation) || - (priv->staging_rxon.ofdm_ht_single_stream_basic_rates != - priv->active_rxon.ofdm_ht_single_stream_basic_rates) || - (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates != - priv->active_rxon.ofdm_ht_dual_stream_basic_rates) || - (priv->staging_rxon.rx_chain != priv->active_rxon.rx_chain) || - (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id)) - return 1; - - /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can - * be updated with the RXON_ASSOC command -- however only some - * flag transitions are allowed using RXON_ASSOC */ - - /* Check if we are not switching bands */ - if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) != - (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)) - return 1; - - /* Check if we are switching association toggle */ - if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) != - (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) - return 1; - - return 0; -} - -/** - * iwl4965_commit_rxon - commit staging_rxon to hardware - * - * The RXON command in staging_rxon is committed to the hardware and - * the active_rxon structure is updated with the new data. This - * function correctly transitions out of the RXON_ASSOC_MSK state if - * a HW tune is required based on the RXON structure changes. - */ -static int iwl4965_commit_rxon(struct iwl_priv *priv) -{ - /* cast away the const for active_rxon in this function */ - struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; - DECLARE_MAC_BUF(mac); - int ret; - bool new_assoc = - !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK); - - if (!iwl_is_alive(priv)) - return -EBUSY; - - /* always get timestamp with Rx frame */ - priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; - /* allow CTS-to-self if possible. this is relevant only for - * 5000, but will not damage 4965 */ - priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN; - - ret = iwl4965_check_rxon_cmd(&priv->staging_rxon); - if (ret) { - IWL_ERROR("Invalid RXON configuration. Not committing.\n"); - return -EINVAL; - } - - /* If we don't need to send a full RXON, we can use - * iwl4965_rxon_assoc_cmd which is used to reconfigure filter - * and other flags for the current radio configuration. */ - if (!iwl4965_full_rxon_required(priv)) { - ret = iwl_send_rxon_assoc(priv); - if (ret) { - IWL_ERROR("Error setting RXON_ASSOC (%d)\n", ret); - return ret; - } - - memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); - return 0; - } - - /* station table will be cleared */ - priv->assoc_station_added = 0; - - /* If we are currently associated and the new config requires - * an RXON_ASSOC and the new config wants the associated mask enabled, - * we must clear the associated from the active configuration - * before we apply the new config */ - if (iwl_is_associated(priv) && new_assoc) { - IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); - active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - - ret = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl_rxon_cmd), - &priv->active_rxon); - - /* If the mask clearing failed then we set - * active_rxon back to what it was previously */ - if (ret) { - active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; - IWL_ERROR("Error clearing ASSOC_MSK (%d)\n", ret); - return ret; - } - } - - IWL_DEBUG_INFO("Sending RXON\n" - "* with%s RXON_FILTER_ASSOC_MSK\n" - "* channel = %d\n" - "* bssid = %s\n", - (new_assoc ? "" : "out"), - le16_to_cpu(priv->staging_rxon.channel), - print_mac(mac, priv->staging_rxon.bssid_addr)); - - iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); - - /* Apply the new configuration - * RXON unassoc clears the station table in uCode, send it before - * we add the bcast station. If assoc bit is set, we will send RXON - * after having added the bcast and bssid station. - */ - if (!new_assoc) { - ret = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); - if (ret) { - IWL_ERROR("Error setting new RXON (%d)\n", ret); - return ret; - } - memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); - } - - iwl_clear_stations_table(priv); - - if (!priv->error_recovering) - priv->start_calib = 0; - - /* Add the broadcast address so we can send broadcast frames */ - if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) == - IWL_INVALID_STATION) { - IWL_ERROR("Error adding BROADCAST address for transmit.\n"); - return -EIO; - } - - /* If we have set the ASSOC_MSK and we are in BSS mode then - * add the IWL_AP_ID to the station rate table */ - if (new_assoc) { - if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { - ret = iwl_rxon_add_station(priv, - priv->active_rxon.bssid_addr, 1); - if (ret == IWL_INVALID_STATION) { - IWL_ERROR("Error adding AP address for TX.\n"); - return -EIO; - } - priv->assoc_station_added = 1; - if (priv->default_wep_key && - iwl_send_static_wepkey_cmd(priv, 0)) - IWL_ERROR("Could not send WEP static key.\n"); - } - - /* Apply the new configuration - * RXON assoc doesn't clear the station table in uCode, - */ - ret = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); - if (ret) { - IWL_ERROR("Error setting new RXON (%d)\n", ret); - return ret; - } - memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); - } - - iwl_init_sensitivity(priv); - - /* If we issue a new RXON command which required a tune then we must - * send a new TXPOWER command or we won't be able to Tx any frames */ - ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); - if (ret) { - IWL_ERROR("Error sending TX power (%d)\n", ret); - return ret; - } - - return 0; -} - -void iwl4965_update_chain_flags(struct iwl_priv *priv) -{ - - iwl_set_rxon_chain(priv); - iwl4965_commit_rxon(priv); -} - -static int iwl4965_send_bt_config(struct iwl_priv *priv) -{ - struct iwl4965_bt_cmd bt_cmd = { - .flags = 3, - .lead_time = 0xAA, - .max_kill = 1, - .kill_ack_mask = 0, - .kill_cts_mask = 0, - }; - - return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, - sizeof(struct iwl4965_bt_cmd), &bt_cmd); -} - -static void iwl_clear_free_frames(struct iwl_priv *priv) -{ - struct list_head *element; - - IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n", - priv->frames_count); - - while (!list_empty(&priv->free_frames)) { - element = priv->free_frames.next; - list_del(element); - kfree(list_entry(element, struct iwl_frame, list)); - priv->frames_count--; - } - - if (priv->frames_count) { - IWL_WARNING("%d frames still in use. Did we lose one?\n", - priv->frames_count); - priv->frames_count = 0; - } -} - -static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) -{ - struct iwl_frame *frame; - struct list_head *element; - if (list_empty(&priv->free_frames)) { - frame = kzalloc(sizeof(*frame), GFP_KERNEL); - if (!frame) { - IWL_ERROR("Could not allocate frame!\n"); - return NULL; - } - - priv->frames_count++; - return frame; - } - - element = priv->free_frames.next; - list_del(element); - return list_entry(element, struct iwl_frame, list); -} - -static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) -{ - memset(frame, 0, sizeof(*frame)); - list_add(&frame->list, &priv->free_frames); -} - -static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, - const u8 *dest, int left) -{ - if (!iwl_is_associated(priv) || !priv->ibss_beacon || - ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) && - (priv->iw_mode != IEEE80211_IF_TYPE_AP))) - return 0; - - if (priv->ibss_beacon->len > left) - return 0; - - memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len); - - return priv->ibss_beacon->len; -} - -static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) -{ - int i; - int rate_mask; - - /* Set rate mask*/ - if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) - rate_mask = priv->active_rate_basic & 0xF; - else - rate_mask = priv->active_rate_basic & 0xFF0; - - /* Find lowest valid rate */ - for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; - i = iwl_rates[i].next_ieee) { - if (rate_mask & (1 << i)) - return iwl_rates[i].plcp; - } - - /* No valid rate was found. Assign the lowest one */ - if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) - return IWL_RATE_1M_PLCP; - else - return IWL_RATE_6M_PLCP; -} - -unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl_frame *frame, u8 rate) -{ - struct iwl_tx_beacon_cmd *tx_beacon_cmd; - unsigned int frame_size; - - tx_beacon_cmd = &frame->u.beacon; - memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); - - tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id; - tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - - frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame, - iwl_bcast_addr, - sizeof(frame->u) - sizeof(*tx_beacon_cmd)); - - BUG_ON(frame_size > MAX_MPDU_SIZE); - tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); - - if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP)) - tx_beacon_cmd->tx.rate_n_flags = - iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK); - else - tx_beacon_cmd->tx.rate_n_flags = - iwl_hw_set_rate_n_flags(rate, 0); - - tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK | - TX_CMD_FLG_TSF_MSK | - TX_CMD_FLG_STA_RATE_MSK; - - return sizeof(*tx_beacon_cmd) + frame_size; -} -static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) -{ - struct iwl_frame *frame; - unsigned int frame_size; - int rc; - u8 rate; - - frame = iwl_get_free_frame(priv); - - if (!frame) { - IWL_ERROR("Could not obtain free frame buffer for beacon " - "command.\n"); - return -ENOMEM; - } - - rate = iwl4965_rate_get_lowest_plcp(priv); - - frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate); - - rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, - &frame->u.cmd[0]); - - iwl_free_frame(priv, frame); - - return rc; -} - -/****************************************************************************** - * - * Misc. internal state and helper functions - * - ******************************************************************************/ - -static void iwl4965_ht_conf(struct iwl_priv *priv, - struct ieee80211_bss_conf *bss_conf) -{ - struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf; - struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf; - struct iwl_ht_info *iwl_conf = &priv->current_ht_config; - - IWL_DEBUG_MAC80211("enter: \n"); - - iwl_conf->is_ht = bss_conf->assoc_ht; - - if (!iwl_conf->is_ht) - return; - - priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); - - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) - iwl_conf->sgf |= HT_SHORT_GI_20MHZ; - if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) - iwl_conf->sgf |= HT_SHORT_GI_40MHZ; - - iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD); - iwl_conf->max_amsdu_size = - !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU); - - iwl_conf->supported_chan_width = - !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH); - iwl_conf->extension_chan_offset = - ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET; - /* If no above or below channel supplied disable FAT channel */ - if (iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_ABOVE && - iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_BELOW) { - iwl_conf->extension_chan_offset = IEEE80211_HT_IE_CHA_SEC_NONE; - iwl_conf->supported_chan_width = 0; - } - - iwl_conf->tx_mimo_ps_mode = - (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2); - memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); - - iwl_conf->control_channel = ht_bss_conf->primary_channel; - iwl_conf->tx_chan_width = - !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH); - iwl_conf->ht_protection = - ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION; - iwl_conf->non_GF_STA_present = - !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT); - - IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel); - IWL_DEBUG_MAC80211("leave\n"); -} - -/* - * QoS support -*/ -static void iwl_activate_qos(struct iwl_priv *priv, u8 force) -{ - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - if (!priv->qos_data.qos_enable) - return; - - priv->qos_data.def_qos_parm.qos_flags = 0; - - if (priv->qos_data.qos_cap.q_AP.queue_request && - !priv->qos_data.qos_cap.q_AP.txop_request) - priv->qos_data.def_qos_parm.qos_flags |= - QOS_PARAM_FLG_TXOP_TYPE_MSK; - if (priv->qos_data.qos_active) - priv->qos_data.def_qos_parm.qos_flags |= - QOS_PARAM_FLG_UPDATE_EDCA_MSK; - - if (priv->current_ht_config.is_ht) - priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; - - if (force || iwl_is_associated(priv)) { - IWL_DEBUG_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n", - priv->qos_data.qos_active, - priv->qos_data.def_qos_parm.qos_flags); - - iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM, - sizeof(struct iwl_qosparam_cmd), - &priv->qos_data.def_qos_parm, NULL); - } -} - -#define MAX_UCODE_BEACON_INTERVAL 4096 - -static __le16 iwl4965_adjust_beacon_interval(u16 beacon_val) -{ - u16 new_val = 0; - u16 beacon_factor = 0; - - beacon_factor = - (beacon_val + MAX_UCODE_BEACON_INTERVAL) - / MAX_UCODE_BEACON_INTERVAL; - new_val = beacon_val / beacon_factor; - - return cpu_to_le16(new_val); -} - -static void iwl4965_setup_rxon_timing(struct iwl_priv *priv) -{ - u64 interval_tm_unit; - u64 tsf, result; - unsigned long flags; - struct ieee80211_conf *conf = NULL; - u16 beacon_int = 0; - - conf = ieee80211_get_hw_conf(priv->hw); - - spin_lock_irqsave(&priv->lock, flags); - priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp >> 32); - priv->rxon_timing.timestamp.dw[0] = - cpu_to_le32(priv->timestamp & 0xFFFFFFFF); - - priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval); - - tsf = priv->timestamp; - - beacon_int = priv->beacon_int; - spin_unlock_irqrestore(&priv->lock, flags); - - if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { - if (beacon_int == 0) { - priv->rxon_timing.beacon_interval = cpu_to_le16(100); - priv->rxon_timing.beacon_init_val = cpu_to_le32(102400); - } else { - priv->rxon_timing.beacon_interval = - cpu_to_le16(beacon_int); - priv->rxon_timing.beacon_interval = - iwl4965_adjust_beacon_interval( - le16_to_cpu(priv->rxon_timing.beacon_interval)); - } - - priv->rxon_timing.atim_window = 0; - } else { - priv->rxon_timing.beacon_interval = - iwl4965_adjust_beacon_interval(conf->beacon_int); - /* TODO: we need to get atim_window from upper stack - * for now we set to 0 */ - priv->rxon_timing.atim_window = 0; - } - - interval_tm_unit = - (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024); - result = do_div(tsf, interval_tm_unit); - priv->rxon_timing.beacon_init_val = - cpu_to_le32((u32) ((u64) interval_tm_unit - result)); - - IWL_DEBUG_ASSOC - ("beacon interval %d beacon timer %d beacon tim %d\n", - le16_to_cpu(priv->rxon_timing.beacon_interval), - le32_to_cpu(priv->rxon_timing.beacon_init_val), - le16_to_cpu(priv->rxon_timing.atim_window)); -} - -static void iwl_set_flags_for_band(struct iwl_priv *priv, - enum ieee80211_band band) -{ - if (band == IEEE80211_BAND_5GHZ) { - priv->staging_rxon.flags &= - ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK - | RXON_FLG_CCK_MSK); - priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; - } else { - /* Copied from iwl4965_post_associate() */ - if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) - priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; - else - priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) - priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - - priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; - priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK; - priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK; - } -} - -/* - * initialize rxon structure with default values from eeprom - */ -static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) -{ - const struct iwl_channel_info *ch_info; - - memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); - - switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_AP: - priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; - break; - - case IEEE80211_IF_TYPE_STA: - priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS; - priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; - break; - - case IEEE80211_IF_TYPE_IBSS: - priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS; - priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK; - priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK | - RXON_FILTER_ACCEPT_GRP_MSK; - break; - - case IEEE80211_IF_TYPE_MNTR: - priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER; - priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK | - RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; - break; - default: - IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode); - break; - } - -#if 0 - /* TODO: Figure out when short_preamble would be set and cache from - * that */ - if (!hw_to_local(priv->hw)->short_preamble) - priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; - else - priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; -#endif - - ch_info = iwl_get_channel_info(priv, priv->band, - le16_to_cpu(priv->active_rxon.channel)); - - if (!ch_info) - ch_info = &priv->channel_info[0]; - - /* - * in some case A channels are all non IBSS - * in this case force B/G channel - */ - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && - !(is_channel_ibss(ch_info))) - ch_info = &priv->channel_info[0]; - - priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); - priv->band = ch_info->band; - - iwl_set_flags_for_band(priv, priv->band); - - priv->staging_rxon.ofdm_basic_rates = - (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; - priv->staging_rxon.cck_basic_rates = - (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; - - priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | - RXON_FLG_CHANNEL_MODE_PURE_40_MSK); - memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); - memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN); - priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff; - priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff; - iwl_set_rxon_chain(priv); -} - -static int iwl4965_set_mode(struct iwl_priv *priv, int mode) -{ - priv->iw_mode = mode; - - iwl4965_connection_init_rx_config(priv); - memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); - - iwl_clear_stations_table(priv); - - /* dont commit rxon if rf-kill is on*/ - if (!iwl_is_ready_rf(priv)) - return -EAGAIN; - - cancel_delayed_work(&priv->scan_check); - if (iwl_scan_cancel_timeout(priv, 100)) { - IWL_WARNING("Aborted scan still in progress after 100ms\n"); - IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); - return -EAGAIN; - } - - iwl4965_commit_rxon(priv); - - return 0; -} - -static void iwl4965_set_rate(struct iwl_priv *priv) -{ - const struct ieee80211_supported_band *hw = NULL; - struct ieee80211_rate *rate; - int i; - - hw = iwl_get_hw_mode(priv, priv->band); - if (!hw) { - IWL_ERROR("Failed to set rate: unable to get hw mode\n"); - return; - } - - priv->active_rate = 0; - priv->active_rate_basic = 0; - - for (i = 0; i < hw->n_bitrates; i++) { - rate = &(hw->bitrates[i]); - if (rate->hw_value < IWL_RATE_COUNT) - priv->active_rate |= (1 << rate->hw_value); - } - - IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n", - priv->active_rate, priv->active_rate_basic); - - /* - * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK) - * otherwise set it to the default of all CCK rates and 6, 12, 24 for - * OFDM - */ - if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK) - priv->staging_rxon.cck_basic_rates = - ((priv->active_rate_basic & - IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF; - else - priv->staging_rxon.cck_basic_rates = - (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; - - if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK) - priv->staging_rxon.ofdm_basic_rates = - ((priv->active_rate_basic & - (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >> - IWL_FIRST_OFDM_RATE) & 0xFF; - else - priv->staging_rxon.ofdm_basic_rates = - (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; -} - -#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT - -#include "iwl-spectrum.h" - -#define BEACON_TIME_MASK_LOW 0x00FFFFFF -#define BEACON_TIME_MASK_HIGH 0xFF000000 -#define TIME_UNIT 1024 - -/* - * extended beacon time format - * time in usec will be changed into a 32-bit value in 8:24 format - * the high 1 byte is the beacon counts - * the lower 3 bytes is the time in usec within one beacon interval - */ - -static u32 iwl4965_usecs_to_beacons(u32 usec, u32 beacon_interval) -{ - u32 quot; - u32 rem; - u32 interval = beacon_interval * 1024; - - if (!interval || !usec) - return 0; - - quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24); - rem = (usec % interval) & BEACON_TIME_MASK_LOW; - - return (quot << 24) + rem; -} - -/* base is usually what we get from ucode with each received frame, - * the same as HW timer counter counting down - */ - -static __le32 iwl4965_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) -{ - u32 base_low = base & BEACON_TIME_MASK_LOW; - u32 addon_low = addon & BEACON_TIME_MASK_LOW; - u32 interval = beacon_interval * TIME_UNIT; - u32 res = (base & BEACON_TIME_MASK_HIGH) + - (addon & BEACON_TIME_MASK_HIGH); - - if (base_low > addon_low) - res += base_low - addon_low; - else if (base_low < addon_low) { - res += interval + base_low - addon_low; - res += (1 << 24); - } else - res += (1 << 24); - - return cpu_to_le32(res); -} - -static int iwl4965_get_measurement(struct iwl_priv *priv, - struct ieee80211_measurement_params *params, - u8 type) -{ - struct iwl4965_spectrum_cmd spectrum; - struct iwl_rx_packet *res; - struct iwl_host_cmd cmd = { - .id = REPLY_SPECTRUM_MEASUREMENT_CMD, - .data = (void *)&spectrum, - .meta.flags = CMD_WANT_SKB, - }; - u32 add_time = le64_to_cpu(params->start_time); - int rc; - int spectrum_resp_status; - int duration = le16_to_cpu(params->duration); - - if (iwl_is_associated(priv)) - add_time = - iwl4965_usecs_to_beacons( - le64_to_cpu(params->start_time) - priv->last_tsf, - le16_to_cpu(priv->rxon_timing.beacon_interval)); - - memset(&spectrum, 0, sizeof(spectrum)); - - spectrum.channel_count = cpu_to_le16(1); - spectrum.flags = - RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK; - spectrum.filter_flags = MEASUREMENT_FILTER_FLAG; - cmd.len = sizeof(spectrum); - spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); - - if (iwl_is_associated(priv)) - spectrum.start_time = - iwl4965_add_beacon_time(priv->last_beacon_time, - add_time, - le16_to_cpu(priv->rxon_timing.beacon_interval)); - else - spectrum.start_time = 0; - - spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT); - spectrum.channels[0].channel = params->channel; - spectrum.channels[0].type = type; - if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK) - spectrum.flags |= RXON_FLG_BAND_24G_MSK | - RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; - - rc = iwl_send_cmd_sync(priv, &cmd); - if (rc) - return rc; - - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n"); - rc = -EIO; - } - - spectrum_resp_status = le16_to_cpu(res->u.spectrum.status); - switch (spectrum_resp_status) { - case 0: /* Command will be handled */ - if (res->u.spectrum.id != 0xff) { - IWL_DEBUG_INFO - ("Replaced existing measurement: %d\n", - res->u.spectrum.id); - priv->measurement_status &= ~MEASUREMENT_READY; - } - priv->measurement_status |= MEASUREMENT_ACTIVE; - rc = 0; - break; - - case 1: /* Command will not be handled */ - rc = -EAGAIN; - break; - } - - dev_kfree_skb_any(cmd.meta.u.skb); - - return rc; -} -#endif - -/****************************************************************************** - * - * Generic RX handler implementations - * - ******************************************************************************/ -static void iwl_rx_reply_alive(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl_alive_resp *palive; - struct delayed_work *pwork; - - palive = &pkt->u.alive_frame; - - IWL_DEBUG_INFO("Alive ucode status 0x%08X revision " - "0x%01X 0x%01X\n", - palive->is_valid, palive->ver_type, - palive->ver_subtype); - - if (palive->ver_subtype == INITIALIZE_SUBTYPE) { - IWL_DEBUG_INFO("Initialization Alive received.\n"); - memcpy(&priv->card_alive_init, - &pkt->u.alive_frame, - sizeof(struct iwl_init_alive_resp)); - pwork = &priv->init_alive_start; - } else { - IWL_DEBUG_INFO("Runtime Alive received.\n"); - memcpy(&priv->card_alive, &pkt->u.alive_frame, - sizeof(struct iwl_alive_resp)); - pwork = &priv->alive_start; - } - - /* We delay the ALIVE response by 5ms to - * give the HW RF Kill time to activate... */ - if (palive->is_valid == UCODE_VALID_OK) - queue_delayed_work(priv->workqueue, pwork, - msecs_to_jiffies(5)); - else - IWL_WARNING("uCode did not respond OK.\n"); -} - -static void iwl4965_rx_reply_error(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - - IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) " - "seq 0x%04X ser 0x%08X\n", - le32_to_cpu(pkt->u.err_resp.error_type), - get_cmd_string(pkt->u.err_resp.cmd_id), - pkt->u.err_resp.cmd_id, - le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num), - le32_to_cpu(pkt->u.err_resp.error_info)); -} - -#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x - -static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; - struct iwl4965_csa_notification *csa = &(pkt->u.csa_notif); - IWL_DEBUG_11H("CSA notif: channel %d, status %d\n", - le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); - rxon->channel = csa->channel; - priv->staging_rxon.channel = csa->channel; -} - -static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ -#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif); - - if (!report->state) { - IWL_DEBUG(IWL_DL_11H, - "Spectrum Measure Notification: Start\n"); - return; - } - - memcpy(&priv->measure_report, report, sizeof(*report)); - priv->measurement_status |= MEASUREMENT_READY; -#endif -} - -static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ -#ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_sleep_notification *sleep = &(pkt->u.sleep_notif); - IWL_DEBUG_RX("sleep mode: %d, src: %d\n", - sleep->pm_sleep_mode, sleep->pm_wakeup_src); -#endif -} - -static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - IWL_DEBUG_RADIO("Dumping %d bytes of unhandled " - "notification for %s:\n", - le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); - iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); -} - -static void iwl4965_bg_beacon_update(struct work_struct *work) -{ - struct iwl_priv *priv = - container_of(work, struct iwl_priv, beacon_update); - struct sk_buff *beacon; - - /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ - beacon = ieee80211_beacon_get(priv->hw, priv->vif); - - if (!beacon) { - IWL_ERROR("update beacon failed\n"); - return; - } - - mutex_lock(&priv->mutex); - /* new beacon skb is allocated every time; dispose previous.*/ - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - priv->ibss_beacon = beacon; - mutex_unlock(&priv->mutex); - - iwl4965_send_beacon_cmd(priv); -} - -/** - * iwl4965_bg_statistics_periodic - Timer callback to queue statistics - * - * This callback is provided in order to send a statistics request. - * - * This timer function is continually reset to execute within - * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION - * was received. We need to ensure we receive the statistics in order - * to update the temperature used for calibrating the TXPOWER. - */ -static void iwl4965_bg_statistics_periodic(unsigned long data) -{ - struct iwl_priv *priv = (struct iwl_priv *)data; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - iwl_send_statistics_request(priv, CMD_ASYNC); -} - -static void iwl4965_rx_beacon_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ -#ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_beacon_notif *beacon = &(pkt->u.beacon_status); - u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); - - IWL_DEBUG_RX("beacon status %x retries %d iss %d " - "tsf %d %d rate %d\n", - le32_to_cpu(beacon->beacon_notify_hdr.u.status) & TX_STATUS_MSK, - beacon->beacon_notify_hdr.failure_frame, - le32_to_cpu(beacon->ibss_mgr_status), - le32_to_cpu(beacon->high_tsf), - le32_to_cpu(beacon->low_tsf), rate); -#endif - - if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && - (!test_bit(STATUS_EXIT_PENDING, &priv->status))) - queue_work(priv->workqueue, &priv->beacon_update); -} - -/* Handle notification from uCode that card's power state is changing - * due to software, hardware, or critical temperature RFKILL */ -static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); - unsigned long status = priv->status; - - IWL_DEBUG_RF_KILL("Card state received: HW:%s SW:%s\n", - (flags & HW_CARD_DISABLED) ? "Kill" : "On", - (flags & SW_CARD_DISABLED) ? "Kill" : "On"); - - if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | - RF_CARD_DISABLED)) { - - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - - if (!iwl_grab_nic_access(priv)) { - iwl_write_direct32( - priv, HBUS_TARG_MBX_C, - HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); - - iwl_release_nic_access(priv); - } - - if (!(flags & RXON_CARD_DISABLED)) { - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - if (!iwl_grab_nic_access(priv)) { - iwl_write_direct32( - priv, HBUS_TARG_MBX_C, - HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); - - iwl_release_nic_access(priv); - } - } - - if (flags & RF_CARD_DISABLED) { - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, - CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); - iwl_read32(priv, CSR_UCODE_DRV_GP1); - if (!iwl_grab_nic_access(priv)) - iwl_release_nic_access(priv); - } - } - - if (flags & HW_CARD_DISABLED) - set_bit(STATUS_RF_KILL_HW, &priv->status); - else - clear_bit(STATUS_RF_KILL_HW, &priv->status); - - - if (flags & SW_CARD_DISABLED) - set_bit(STATUS_RF_KILL_SW, &priv->status); - else - clear_bit(STATUS_RF_KILL_SW, &priv->status); - - if (!(flags & RXON_CARD_DISABLED)) - iwl_scan_cancel(priv); - - if ((test_bit(STATUS_RF_KILL_HW, &status) != - test_bit(STATUS_RF_KILL_HW, &priv->status)) || - (test_bit(STATUS_RF_KILL_SW, &status) != - test_bit(STATUS_RF_KILL_SW, &priv->status))) - queue_work(priv->workqueue, &priv->rf_kill); - else - wake_up_interruptible(&priv->wait_command_queue); -} - -int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) -{ - int ret; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) - goto err; - - if (src == IWL_PWR_SRC_VAUX) { - u32 val; - ret = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE, - &val); - - if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) - iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_PWR_SRC_VAUX, - ~APMG_PS_CTRL_MSK_PWR_SRC); - } else { - iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, - ~APMG_PS_CTRL_MSK_PWR_SRC); - } - - iwl_release_nic_access(priv); -err: - spin_unlock_irqrestore(&priv->lock, flags); - return ret; -} - -/** - * iwl4965_setup_rx_handlers - Initialize Rx handler callbacks - * - * Setup the RX handlers for each of the reply types sent from the uCode - * to the host. - * - * This function chains into the hardware specific files for them to setup - * any hardware specific handlers as well. - */ -static void iwl_setup_rx_handlers(struct iwl_priv *priv) -{ - priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; - priv->rx_handlers[REPLY_ERROR] = iwl4965_rx_reply_error; - priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl4965_rx_csa; - priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = - iwl4965_rx_spectrum_measure_notif; - priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl4965_rx_pm_sleep_notif; - priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = - iwl4965_rx_pm_debug_statistics_notif; - priv->rx_handlers[BEACON_NOTIFICATION] = iwl4965_rx_beacon_notif; - - /* - * The same handler is used for both the REPLY to a discrete - * statistics request from the host as well as for the periodic - * statistics notifications (after received beacons) from the uCode. - */ - priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_rx_statistics; - priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; - - iwl_setup_rx_scan_handlers(priv); - - /* status change handler */ - priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif; - - priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = - iwl_rx_missed_beacon_notif; - /* Rx handlers */ - priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl_rx_reply_rx_phy; - priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl_rx_reply_rx; - /* block ack */ - priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl_rx_reply_compressed_ba; - /* Set up hardware specific Rx handlers */ - priv->cfg->ops->lib->rx_handler_setup(priv); -} - -/* - * this should be called while priv->lock is locked -*/ -static void __iwl_rx_replenish(struct iwl_priv *priv) -{ - iwl_rx_allocate(priv); - iwl_rx_queue_restock(priv); -} - - -/** - * iwl_rx_handle - Main entry function for receiving responses from uCode - * - * Uses the priv->rx_handlers callback function array to invoke - * the appropriate handlers, including command responses, - * frame-received notifications, and other notifications. - */ -void iwl_rx_handle(struct iwl_priv *priv) -{ - struct iwl_rx_mem_buffer *rxb; - struct iwl_rx_packet *pkt; - struct iwl_rx_queue *rxq = &priv->rxq; - u32 r, i; - int reclaim; - unsigned long flags; - u8 fill_rx = 0; - u32 count = 8; - - /* uCode's read index (stored in shared DRAM) indicates the last Rx - * buffer that the driver may process (last buffer filled by ucode). */ - r = priv->cfg->ops->lib->shared_mem_rx_idx(priv); - i = rxq->read; - - /* Rx interrupt, but nothing sent from uCode */ - if (i == r) - IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d\n", r, i); - - if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) - fill_rx = 1; - - while (i != r) { - rxb = rxq->queue[i]; - - /* If an RXB doesn't have a Rx queue slot associated with it, - * then a bug has been introduced in the queue refilling - * routines -- catch it here */ - BUG_ON(rxb == NULL); - - rxq->queue[i] = NULL; - - pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, - priv->hw_params.rx_buf_size, - PCI_DMA_FROMDEVICE); - pkt = (struct iwl_rx_packet *)rxb->skb->data; - - /* Reclaim a command buffer only if this packet is a response - * to a (driver-originated) command. - * If the packet (e.g. Rx frame) originated from uCode, - * there is no command buffer to reclaim. - * Ucode should set SEQ_RX_FRAME bit if ucode-originated, - * but apparently a few don't get set; catch them here. */ - reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && - (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && - (pkt->hdr.cmd != REPLY_RX) && - (pkt->hdr.cmd != REPLY_COMPRESSED_BA) && - (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && - (pkt->hdr.cmd != REPLY_TX); - - /* Based on type of command response or notification, - * handle those that need handling via function in - * rx_handlers table. See iwl4965_setup_rx_handlers() */ - if (priv->rx_handlers[pkt->hdr.cmd]) { - IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d, %s, 0x%02x\n", r, - i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); - priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); - } else { - /* No handling needed */ - IWL_DEBUG(IWL_DL_RX, - "r %d i %d No handler needed for %s, 0x%02x\n", - r, i, get_cmd_string(pkt->hdr.cmd), - pkt->hdr.cmd); - } - - if (reclaim) { - /* Invoke any callbacks, transfer the skb to caller, and - * fire off the (possibly) blocking iwl_send_cmd() - * as we reclaim the driver command queue */ - if (rxb && rxb->skb) - iwl_tx_cmd_complete(priv, rxb); - else - IWL_WARNING("Claim null rxb?\n"); - } - - /* For now we just don't re-use anything. We can tweak this - * later to try and re-use notification packets and SKBs that - * fail to Rx correctly */ - if (rxb->skb != NULL) { - priv->alloc_rxb_skb--; - dev_kfree_skb_any(rxb->skb); - rxb->skb = NULL; - } - - pci_unmap_single(priv->pci_dev, rxb->dma_addr, - priv->hw_params.rx_buf_size, - PCI_DMA_FROMDEVICE); - spin_lock_irqsave(&rxq->lock, flags); - list_add_tail(&rxb->list, &priv->rxq.rx_used); - spin_unlock_irqrestore(&rxq->lock, flags); - i = (i + 1) & RX_QUEUE_MASK; - /* If there are a lot of unused frames, - * restock the Rx queue so ucode wont assert. */ - if (fill_rx) { - count++; - if (count >= 8) { - priv->rxq.read = i; - __iwl_rx_replenish(priv); - count = 0; - } - } - } - - /* Backtrack one entry */ - priv->rxq.read = i; - iwl_rx_queue_restock(priv); -} - -#ifdef CONFIG_IWLWIFI_DEBUG -static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) -{ - struct iwl_rxon_cmd *rxon = &priv->staging_rxon; - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_RADIO("RX CONFIG:\n"); - iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); - IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); - IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); - IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n", - le32_to_cpu(rxon->filter_flags)); - IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type); - IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", - rxon->ofdm_basic_rates); - IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); - IWL_DEBUG_RADIO("u8[6] node_addr: %s\n", - print_mac(mac, rxon->node_addr)); - IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n", - print_mac(mac, rxon->bssid_addr)); - IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); -} -#endif - -static void iwl4965_enable_interrupts(struct iwl_priv *priv) -{ - IWL_DEBUG_ISR("Enabling interrupts\n"); - set_bit(STATUS_INT_ENABLED, &priv->status); - iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); -} - -/* call this function to flush any scheduled tasklet */ -static inline void iwl_synchronize_irq(struct iwl_priv *priv) -{ - /* wait to make sure we flush pedding tasklet*/ - synchronize_irq(priv->pci_dev->irq); - tasklet_kill(&priv->irq_tasklet); -} - -static inline void iwl4965_disable_interrupts(struct iwl_priv *priv) -{ - clear_bit(STATUS_INT_ENABLED, &priv->status); - - /* disable interrupts from uCode/NIC to host */ - iwl_write32(priv, CSR_INT_MASK, 0x00000000); - - /* acknowledge/clear/reset any interrupts still pending - * from uCode or flow handler (Rx/Tx DMA) */ - iwl_write32(priv, CSR_INT, 0xffffffff); - iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); - IWL_DEBUG_ISR("Disabled interrupts\n"); -} - - -/** - * iwl4965_irq_handle_error - called for HW or SW error interrupt from card - */ -static void iwl4965_irq_handle_error(struct iwl_priv *priv) -{ - /* Set the FW error flag -- cleared on iwl4965_down */ - set_bit(STATUS_FW_ERROR, &priv->status); - - /* Cancel currently queued command. */ - clear_bit(STATUS_HCMD_ACTIVE, &priv->status); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & IWL_DL_FW_ERRORS) { - iwl_dump_nic_error_log(priv); - iwl_dump_nic_event_log(priv); - iwl4965_print_rx_config_cmd(priv); - } -#endif - - wake_up_interruptible(&priv->wait_command_queue); - - /* Keep the restart process from trying to send host - * commands by clearing the INIT status bit */ - clear_bit(STATUS_READY, &priv->status); - - if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { - IWL_DEBUG(IWL_DL_FW_ERRORS, - "Restarting adapter due to uCode error.\n"); - - if (iwl_is_associated(priv)) { - memcpy(&priv->recovery_rxon, &priv->active_rxon, - sizeof(priv->recovery_rxon)); - priv->error_recovering = 1; - } - if (priv->cfg->mod_params->restart_fw) - queue_work(priv->workqueue, &priv->restart); - } -} - -static void iwl4965_error_recovery(struct iwl_priv *priv) -{ - unsigned long flags; - - memcpy(&priv->staging_rxon, &priv->recovery_rxon, - sizeof(priv->staging_rxon)); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); - - iwl_rxon_add_station(priv, priv->bssid, 1); - - spin_lock_irqsave(&priv->lock, flags); - priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); - priv->error_recovering = 0; - spin_unlock_irqrestore(&priv->lock, flags); -} - -static void iwl4965_irq_tasklet(struct iwl_priv *priv) -{ - u32 inta, handled = 0; - u32 inta_fh; - unsigned long flags; -#ifdef CONFIG_IWLWIFI_DEBUG - u32 inta_mask; -#endif - - spin_lock_irqsave(&priv->lock, flags); - - /* Ack/clear/reset pending uCode interrupts. - * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, - * and will clear only when CSR_FH_INT_STATUS gets cleared. */ - inta = iwl_read32(priv, CSR_INT); - iwl_write32(priv, CSR_INT, inta); - - /* Ack/clear/reset pending flow-handler (DMA) interrupts. - * Any new interrupts that happen after this, either while we're - * in this tasklet, or later, will show up in next ISR/tasklet. */ - inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); - iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & IWL_DL_ISR) { - /* just for debug */ - inta_mask = iwl_read32(priv, CSR_INT_MASK); - IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", - inta, inta_mask, inta_fh); - } -#endif - - /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not - * atomic, make sure that inta covers all the interrupts that - * we've discovered, even if FH interrupt came in just after - * reading CSR_INT. */ - if (inta_fh & CSR49_FH_INT_RX_MASK) - inta |= CSR_INT_BIT_FH_RX; - if (inta_fh & CSR49_FH_INT_TX_MASK) - inta |= CSR_INT_BIT_FH_TX; - - /* Now service all interrupt bits discovered above. */ - if (inta & CSR_INT_BIT_HW_ERR) { - IWL_ERROR("Microcode HW error detected. Restarting.\n"); - - /* Tell the device to stop sending interrupts */ - iwl4965_disable_interrupts(priv); - - iwl4965_irq_handle_error(priv); - - handled |= CSR_INT_BIT_HW_ERR; - - spin_unlock_irqrestore(&priv->lock, flags); - - return; - } - -#ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & (IWL_DL_ISR)) { - /* NIC fires this, but we don't use it, redundant with WAKEUP */ - if (inta & CSR_INT_BIT_SCD) - IWL_DEBUG_ISR("Scheduler finished to transmit " - "the frame/frames.\n"); - - /* Alive notification via Rx interrupt will do the real work */ - if (inta & CSR_INT_BIT_ALIVE) - IWL_DEBUG_ISR("Alive interrupt\n"); - } -#endif - /* Safely ignore these bits for debug checks below */ - inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); - - /* HW RF KILL switch toggled */ - if (inta & CSR_INT_BIT_RF_KILL) { - int hw_rf_kill = 0; - if (!(iwl_read32(priv, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) - hw_rf_kill = 1; - - IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n", - hw_rf_kill ? "disable radio":"enable radio"); - - /* driver only loads ucode once setting the interface up. - * the driver as well won't allow loading if RFKILL is set - * therefore no need to restart the driver from this handler - */ - if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) - clear_bit(STATUS_RF_KILL_HW, &priv->status); - - handled |= CSR_INT_BIT_RF_KILL; - } - - /* Chip got too hot and stopped itself */ - if (inta & CSR_INT_BIT_CT_KILL) { - IWL_ERROR("Microcode CT kill error detected.\n"); - handled |= CSR_INT_BIT_CT_KILL; - } - - /* Error detected by uCode */ - if (inta & CSR_INT_BIT_SW_ERR) { - IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n", - inta); - iwl4965_irq_handle_error(priv); - handled |= CSR_INT_BIT_SW_ERR; - } - - /* uCode wakes up after power-down sleep */ - if (inta & CSR_INT_BIT_WAKEUP) { - IWL_DEBUG_ISR("Wakeup interrupt\n"); - iwl_rx_queue_update_write_ptr(priv, &priv->rxq); - iwl_txq_update_write_ptr(priv, &priv->txq[0]); - iwl_txq_update_write_ptr(priv, &priv->txq[1]); - iwl_txq_update_write_ptr(priv, &priv->txq[2]); - iwl_txq_update_write_ptr(priv, &priv->txq[3]); - iwl_txq_update_write_ptr(priv, &priv->txq[4]); - iwl_txq_update_write_ptr(priv, &priv->txq[5]); - - handled |= CSR_INT_BIT_WAKEUP; - } - - /* All uCode command responses, including Tx command responses, - * Rx "responses" (frame-received notification), and other - * notifications from uCode come through here*/ - if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { - iwl_rx_handle(priv); - handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); - } - - if (inta & CSR_INT_BIT_FH_TX) { - IWL_DEBUG_ISR("Tx interrupt\n"); - handled |= CSR_INT_BIT_FH_TX; - /* FH finished to write, send event */ - priv->ucode_write_complete = 1; - wake_up_interruptible(&priv->wait_command_queue); - } - - if (inta & ~handled) - IWL_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); - - if (inta & ~CSR_INI_SET_MASK) { - IWL_WARNING("Disabled INTA bits 0x%08x were pending\n", - inta & ~CSR_INI_SET_MASK); - IWL_WARNING(" with FH_INT = 0x%08x\n", inta_fh); - } - - /* Re-enable all interrupts */ - /* only Re-enable if diabled by irq */ - if (test_bit(STATUS_INT_ENABLED, &priv->status)) - iwl4965_enable_interrupts(priv); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (priv->debug_level & (IWL_DL_ISR)) { - inta = iwl_read32(priv, CSR_INT); - inta_mask = iwl_read32(priv, CSR_INT_MASK); - inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); - IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, " - "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); - } -#endif - spin_unlock_irqrestore(&priv->lock, flags); -} - -static irqreturn_t iwl4965_isr(int irq, void *data) -{ - struct iwl_priv *priv = data; - u32 inta, inta_mask; - u32 inta_fh; - if (!priv) - return IRQ_NONE; - - spin_lock(&priv->lock); - - /* Disable (but don't clear!) interrupts here to avoid - * back-to-back ISRs and sporadic interrupts from our NIC. - * If we have something to service, the tasklet will re-enable ints. - * If we *don't* have something, we'll re-enable before leaving here. */ - inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ - iwl_write32(priv, CSR_INT_MASK, 0x00000000); - - /* Discover which interrupts are active/pending */ - inta = iwl_read32(priv, CSR_INT); - inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); - - /* Ignore interrupt if there's nothing in NIC to service. - * This may be due to IRQ shared with another device, - * or due to sporadic interrupts thrown from our NIC. */ - if (!inta && !inta_fh) { - IWL_DEBUG_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n"); - goto none; - } - - if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { - /* Hardware disappeared. It might have already raised - * an interrupt */ - IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta); - goto unplugged; - } - - IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", - inta, inta_mask, inta_fh); - - inta &= ~CSR_INT_BIT_SCD; - - /* iwl4965_irq_tasklet() will service interrupts and re-enable them */ - if (likely(inta || inta_fh)) - tasklet_schedule(&priv->irq_tasklet); - - unplugged: - spin_unlock(&priv->lock); - return IRQ_HANDLED; - - none: - /* re-enable interrupts here since we don't have anything to service. */ - /* only Re-enable if diabled by irq */ - if (test_bit(STATUS_INT_ENABLED, &priv->status)) - iwl4965_enable_interrupts(priv); - spin_unlock(&priv->lock); - return IRQ_NONE; -} - -/****************************************************************************** - * - * uCode download functions - * - ******************************************************************************/ - -static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv) -{ - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); -} - -static void iwl4965_nic_start(struct iwl_priv *priv) -{ - /* Remove all resets to allow NIC to operate */ - iwl_write32(priv, CSR_RESET, 0); -} - - -/** - * iwl4965_read_ucode - Read uCode images from disk file. - * - * Copy into buffers for card to fetch via bus-mastering - */ -static int iwl4965_read_ucode(struct iwl_priv *priv) -{ - struct iwl_ucode *ucode; - int ret; - const struct firmware *ucode_raw; - const char *name = priv->cfg->fw_name; - u8 *src; - size_t len; - u32 ver, inst_size, data_size, init_size, init_data_size, boot_size; - - /* Ask kernel firmware_class module to get the boot firmware off disk. - * request_firmware() is synchronous, file is in memory on return. */ - ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev); - if (ret < 0) { - IWL_ERROR("%s firmware file req failed: Reason %d\n", - name, ret); - goto error; - } - - IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", - name, ucode_raw->size); - - /* Make sure that we got at least our header! */ - if (ucode_raw->size < sizeof(*ucode)) { - IWL_ERROR("File size way too small!\n"); - ret = -EINVAL; - goto err_release; - } - - /* Data from ucode file: header followed by uCode images */ - ucode = (void *)ucode_raw->data; - - ver = le32_to_cpu(ucode->ver); - inst_size = le32_to_cpu(ucode->inst_size); - data_size = le32_to_cpu(ucode->data_size); - init_size = le32_to_cpu(ucode->init_size); - init_data_size = le32_to_cpu(ucode->init_data_size); - boot_size = le32_to_cpu(ucode->boot_size); - - IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver); - IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", - inst_size); - IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", - data_size); - IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n", - init_size); - IWL_DEBUG_INFO("f/w package hdr init data size = %u\n", - init_data_size); - IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n", - boot_size); - - /* Verify size of file vs. image size info in file's header */ - if (ucode_raw->size < sizeof(*ucode) + - inst_size + data_size + init_size + - init_data_size + boot_size) { - - IWL_DEBUG_INFO("uCode file size %d too small\n", - (int)ucode_raw->size); - ret = -EINVAL; - goto err_release; - } - - /* Verify that uCode images will fit in card's SRAM */ - if (inst_size > priv->hw_params.max_inst_size) { - IWL_DEBUG_INFO("uCode instr len %d too large to fit in\n", - inst_size); - ret = -EINVAL; - goto err_release; - } - - if (data_size > priv->hw_params.max_data_size) { - IWL_DEBUG_INFO("uCode data len %d too large to fit in\n", - data_size); - ret = -EINVAL; - goto err_release; - } - if (init_size > priv->hw_params.max_inst_size) { - IWL_DEBUG_INFO - ("uCode init instr len %d too large to fit in\n", - init_size); - ret = -EINVAL; - goto err_release; - } - if (init_data_size > priv->hw_params.max_data_size) { - IWL_DEBUG_INFO - ("uCode init data len %d too large to fit in\n", - init_data_size); - ret = -EINVAL; - goto err_release; - } - if (boot_size > priv->hw_params.max_bsm_size) { - IWL_DEBUG_INFO - ("uCode boot instr len %d too large to fit in\n", - boot_size); - ret = -EINVAL; - goto err_release; - } - - /* Allocate ucode buffers for card's bus-master loading ... */ - - /* Runtime instructions and 2 copies of data: - * 1) unmodified from disk - * 2) backup cache for save/restore during power-downs */ - priv->ucode_code.len = inst_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code); - - priv->ucode_data.len = data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data); - - priv->ucode_data_backup.len = data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup); - - /* Initialization instructions and data */ - if (init_size && init_data_size) { - priv->ucode_init.len = init_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init); - - priv->ucode_init_data.len = init_data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data); - - if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr) - goto err_pci_alloc; - } - - /* Bootstrap (instructions only, no data) */ - if (boot_size) { - priv->ucode_boot.len = boot_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot); - - if (!priv->ucode_boot.v_addr) - goto err_pci_alloc; - } - - /* Copy images into buffers for card's bus-master reads ... */ - - /* Runtime instructions (first block of data in file) */ - src = &ucode->data[0]; - len = priv->ucode_code.len; - IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %Zd\n", len); - memcpy(priv->ucode_code.v_addr, src, len); - IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", - priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); - - /* Runtime data (2nd block) - * NOTE: Copy into backup buffer will be done in iwl4965_up() */ - src = &ucode->data[inst_size]; - len = priv->ucode_data.len; - IWL_DEBUG_INFO("Copying (but not loading) uCode data len %Zd\n", len); - memcpy(priv->ucode_data.v_addr, src, len); - memcpy(priv->ucode_data_backup.v_addr, src, len); - - /* Initialization instructions (3rd block) */ - if (init_size) { - src = &ucode->data[inst_size + data_size]; - len = priv->ucode_init.len; - IWL_DEBUG_INFO("Copying (but not loading) init instr len %Zd\n", - len); - memcpy(priv->ucode_init.v_addr, src, len); - } - - /* Initialization data (4th block) */ - if (init_data_size) { - src = &ucode->data[inst_size + data_size + init_size]; - len = priv->ucode_init_data.len; - IWL_DEBUG_INFO("Copying (but not loading) init data len %Zd\n", - len); - memcpy(priv->ucode_init_data.v_addr, src, len); - } - - /* Bootstrap instructions (5th block) */ - src = &ucode->data[inst_size + data_size + init_size + init_data_size]; - len = priv->ucode_boot.len; - IWL_DEBUG_INFO("Copying (but not loading) boot instr len %Zd\n", len); - memcpy(priv->ucode_boot.v_addr, src, len); - - /* We have our copies now, allow OS release its copies */ - release_firmware(ucode_raw); - return 0; - - err_pci_alloc: - IWL_ERROR("failed to allocate pci memory\n"); - ret = -ENOMEM; - iwl4965_dealloc_ucode_pci(priv); - - err_release: - release_firmware(ucode_raw); - - error: - return ret; -} - -/** - * iwl_alive_start - called after REPLY_ALIVE notification received - * from protocol/runtime uCode (initialization uCode's - * Alive gets handled by iwl_init_alive_start()). - */ -static void iwl_alive_start(struct iwl_priv *priv) -{ - int ret = 0; - - IWL_DEBUG_INFO("Runtime Alive received.\n"); - - if (priv->card_alive.is_valid != UCODE_VALID_OK) { - /* We had an error bringing up the hardware, so take it - * all the way back down so we can try again */ - IWL_DEBUG_INFO("Alive failed.\n"); - goto restart; - } - - /* Initialize uCode has loaded Runtime uCode ... verify inst image. - * This is a paranoid check, because we would not have gotten the - * "runtime" alive if code weren't properly loaded. */ - if (iwl_verify_ucode(priv)) { - /* Runtime instruction load was bad; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO("Bad runtime uCode load.\n"); - goto restart; - } - - iwl_clear_stations_table(priv); - ret = priv->cfg->ops->lib->alive_notify(priv); - if (ret) { - IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n", - ret); - goto restart; - } - - /* After the ALIVE response, we can send host commands to 4965 uCode */ - set_bit(STATUS_ALIVE, &priv->status); - - if (iwl_is_rfkill(priv)) - return; - - ieee80211_wake_queues(priv->hw); - - priv->active_rate = priv->rates_mask; - priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; - - if (iwl_is_associated(priv)) { - struct iwl_rxon_cmd *active_rxon = - (struct iwl_rxon_cmd *)&priv->active_rxon; - - memcpy(&priv->staging_rxon, &priv->active_rxon, - sizeof(priv->staging_rxon)); - active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - } else { - /* Initialize our rx_config data */ - iwl4965_connection_init_rx_config(priv); - memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); - } - - /* Configure Bluetooth device coexistence support */ - iwl4965_send_bt_config(priv); - - iwl_reset_run_time_calib(priv); - - /* Configure the adapter for unassociated operation */ - iwl4965_commit_rxon(priv); - - /* At this point, the NIC is initialized and operational */ - iwl_rf_kill_ct_config(priv); - - iwl_leds_register(priv); - - IWL_DEBUG_INFO("ALIVE processing complete.\n"); - set_bit(STATUS_READY, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); - - if (priv->error_recovering) - iwl4965_error_recovery(priv); - - iwl_power_update_mode(priv, 1); - ieee80211_notify_mac(priv->hw, IEEE80211_NOTIFY_RE_ASSOC); - - if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status)) - iwl4965_set_mode(priv, priv->iw_mode); - - return; - - restart: - queue_work(priv->workqueue, &priv->restart); -} - -static void iwl_cancel_deferred_work(struct iwl_priv *priv); - -static void __iwl4965_down(struct iwl_priv *priv) -{ - unsigned long flags; - int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); - - IWL_DEBUG_INFO(DRV_NAME " is going down\n"); - - if (!exit_pending) - set_bit(STATUS_EXIT_PENDING, &priv->status); - - iwl_leds_unregister(priv); - - iwl_clear_stations_table(priv); - - /* Unblock any waiting calls */ - wake_up_interruptible_all(&priv->wait_command_queue); - - /* Wipe out the EXIT_PENDING status bit if we are not actually - * exiting the module */ - if (!exit_pending) - clear_bit(STATUS_EXIT_PENDING, &priv->status); - - /* stop and reset the on-board processor */ - iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); - - /* tell the device to stop sending interrupts */ - spin_lock_irqsave(&priv->lock, flags); - iwl4965_disable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - iwl_synchronize_irq(priv); - - if (priv->mac80211_registered) - ieee80211_stop_queues(priv->hw); - - /* If we have not previously called iwl4965_init() then - * clear all bits but the RF Kill and SUSPEND bits and return */ - if (!iwl_is_init(priv)) { - priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << - STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | - test_bit(STATUS_GEO_CONFIGURED, &priv->status) << - STATUS_GEO_CONFIGURED | - test_bit(STATUS_IN_SUSPEND, &priv->status) << - STATUS_IN_SUSPEND | - test_bit(STATUS_EXIT_PENDING, &priv->status) << - STATUS_EXIT_PENDING; - goto exit; - } - - /* ...otherwise clear out all the status bits but the RF Kill and - * SUSPEND bits and continue taking the NIC down. */ - priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << - STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | - test_bit(STATUS_GEO_CONFIGURED, &priv->status) << - STATUS_GEO_CONFIGURED | - test_bit(STATUS_IN_SUSPEND, &priv->status) << - STATUS_IN_SUSPEND | - test_bit(STATUS_FW_ERROR, &priv->status) << - STATUS_FW_ERROR | - test_bit(STATUS_EXIT_PENDING, &priv->status) << - STATUS_EXIT_PENDING; - - spin_lock_irqsave(&priv->lock, flags); - iwl_clear_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - spin_unlock_irqrestore(&priv->lock, flags); - - iwl_txq_ctx_stop(priv); - iwl_rxq_stop(priv); - - spin_lock_irqsave(&priv->lock, flags); - if (!iwl_grab_nic_access(priv)) { - iwl_write_prph(priv, APMG_CLK_DIS_REG, - APMG_CLK_VAL_DMA_CLK_RQT); - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->lock, flags); - - udelay(5); - - /* FIXME: apm_ops.suspend(priv) */ - priv->cfg->ops->lib->apm_ops.reset(priv); - priv->cfg->ops->lib->free_shared_mem(priv); - - exit: - memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); - - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - priv->ibss_beacon = NULL; - - /* clear out any free frames */ - iwl_clear_free_frames(priv); -} - -static void iwl4965_down(struct iwl_priv *priv) -{ - mutex_lock(&priv->mutex); - __iwl4965_down(priv); - mutex_unlock(&priv->mutex); - - iwl_cancel_deferred_work(priv); -} - -#define MAX_HW_RESTARTS 5 - -static int __iwl4965_up(struct iwl_priv *priv) -{ - int i; - int ret; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { - IWL_WARNING("Exit pending; will not bring the NIC up\n"); - return -EIO; - } - - if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { - IWL_ERROR("ucode not available for device bringup\n"); - return -EIO; - } - - /* If platform's RF_KILL switch is NOT set to KILL */ - if (iwl_read32(priv, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) - clear_bit(STATUS_RF_KILL_HW, &priv->status); - else - set_bit(STATUS_RF_KILL_HW, &priv->status); - - if (!test_bit(STATUS_IN_SUSPEND, &priv->status) && - iwl_is_rfkill(priv)) { - IWL_WARNING("Radio disabled by %s RF Kill switch\n", - test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW"); - return -ENODEV; - } - - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - - ret = priv->cfg->ops->lib->alloc_shared_mem(priv); - if (ret) { - IWL_ERROR("Unable to allocate shared memory\n"); - return ret; - } - - ret = iwl_hw_nic_init(priv); - if (ret) { - IWL_ERROR("Unable to init nic\n"); - return ret; - } - - /* make sure rfkill handshake bits are cleared */ - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - - /* clear (again), then enable host interrupts */ - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - iwl4965_enable_interrupts(priv); - - /* really make sure rfkill handshake bits are cleared */ - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - - /* Copy original ucode data image from disk into backup cache. - * This will be used to initialize the on-board processor's - * data SRAM for a clean start when the runtime program first loads. */ - memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, - priv->ucode_data.len); - - /* We return success when we resume from suspend and rf_kill is on. */ - if (test_bit(STATUS_RF_KILL_HW, &priv->status) || - test_bit(STATUS_RF_KILL_SW, &priv->status)) - return 0; - - for (i = 0; i < MAX_HW_RESTARTS; i++) { - - iwl_clear_stations_table(priv); - - /* load bootstrap state machine, - * load bootstrap program into processor's memory, - * prepare to load the "initialize" uCode */ - ret = priv->cfg->ops->lib->load_ucode(priv); - - if (ret) { - IWL_ERROR("Unable to set up bootstrap uCode: %d\n", ret); - continue; - } - - /* Clear out the uCode error bit if it is set */ - clear_bit(STATUS_FW_ERROR, &priv->status); - - /* start card; "initialize" will load runtime ucode */ - iwl4965_nic_start(priv); - - IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); - - return 0; - } - - set_bit(STATUS_EXIT_PENDING, &priv->status); - __iwl4965_down(priv); - clear_bit(STATUS_EXIT_PENDING, &priv->status); - - /* tried to restart and config the device for as long as our - * patience could withstand */ - IWL_ERROR("Unable to initialize device after %d attempts.\n", i); - return -EIO; -} - - -/***************************************************************************** - * - * Workqueue callbacks - * - *****************************************************************************/ - -static void iwl_bg_init_alive_start(struct work_struct *data) -{ - struct iwl_priv *priv = - container_of(data, struct iwl_priv, init_alive_start.work); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - priv->cfg->ops->lib->init_alive_start(priv); - mutex_unlock(&priv->mutex); -} - -static void iwl_bg_alive_start(struct work_struct *data) -{ - struct iwl_priv *priv = - container_of(data, struct iwl_priv, alive_start.work); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - iwl_alive_start(priv); - mutex_unlock(&priv->mutex); -} - -static void iwl4965_bg_rf_kill(struct work_struct *work) -{ - struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); - - wake_up_interruptible(&priv->wait_command_queue); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - - if (!iwl_is_rfkill(priv)) { - IWL_DEBUG(IWL_DL_RF_KILL, - "HW and/or SW RF Kill no longer active, restarting " - "device\n"); - if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) - queue_work(priv->workqueue, &priv->restart); - } else { - /* make sure mac80211 stop sending Tx frame */ - if (priv->mac80211_registered) - ieee80211_stop_queues(priv->hw); - - if (!test_bit(STATUS_RF_KILL_HW, &priv->status)) - IWL_DEBUG_RF_KILL("Can not turn radio back on - " - "disabled by SW switch\n"); - else - IWL_WARNING("Radio Frequency Kill Switch is On:\n" - "Kill switch must be turned off for " - "wireless networking to work.\n"); - } - mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); -} - -static void iwl4965_bg_set_monitor(struct work_struct *work) -{ - struct iwl_priv *priv = container_of(work, - struct iwl_priv, set_monitor); - int ret; - - IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n"); - - mutex_lock(&priv->mutex); - - ret = iwl4965_set_mode(priv, IEEE80211_IF_TYPE_MNTR); - - if (ret) { - if (ret == -EAGAIN) - IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n"); - else - IWL_ERROR("iwl4965_set_mode() failed ret = %d\n", ret); - } - - mutex_unlock(&priv->mutex); -} - -static void iwl_bg_run_time_calib_work(struct work_struct *work) -{ - struct iwl_priv *priv = container_of(work, struct iwl_priv, - run_time_calib_work); - - mutex_lock(&priv->mutex); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status) || - test_bit(STATUS_SCANNING, &priv->status)) { - mutex_unlock(&priv->mutex); - return; - } - - if (priv->start_calib) { - iwl_chain_noise_calibration(priv, &priv->statistics); - - iwl_sensitivity_calibration(priv, &priv->statistics); - } - - mutex_unlock(&priv->mutex); - return; -} - -static void iwl4965_bg_up(struct work_struct *data) -{ - struct iwl_priv *priv = container_of(data, struct iwl_priv, up); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - __iwl4965_up(priv); - mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); -} - -static void iwl4965_bg_restart(struct work_struct *data) -{ - struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - iwl4965_down(priv); - queue_work(priv->workqueue, &priv->up); -} - -static void iwl4965_bg_rx_replenish(struct work_struct *data) -{ - struct iwl_priv *priv = - container_of(data, struct iwl_priv, rx_replenish); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - iwl_rx_replenish(priv); - mutex_unlock(&priv->mutex); -} - -#define IWL_DELAY_NEXT_SCAN (HZ*2) - -static void iwl4965_post_associate(struct iwl_priv *priv) -{ - struct ieee80211_conf *conf = NULL; - int ret = 0; - DECLARE_MAC_BUF(mac); - unsigned long flags; - - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { - IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__); - return; - } - - IWL_DEBUG_ASSOC("Associated as %d to: %s\n", - priv->assoc_id, - print_mac(mac, priv->active_rxon.bssid_addr)); - - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - - if (!priv->vif || !priv->is_open) - return; - - iwl_scan_cancel_timeout(priv, 200); - - conf = ieee80211_get_hw_conf(priv->hw); - - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); - - memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd)); - iwl4965_setup_rxon_timing(priv); - ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, - sizeof(priv->rxon_timing), &priv->rxon_timing); - if (ret) - IWL_WARNING("REPLY_RXON_TIMING failed - " - "Attempting to continue.\n"); - - priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; - - if (priv->current_ht_config.is_ht) - iwl_set_rxon_ht(priv, &priv->current_ht_config); - - iwl_set_rxon_chain(priv); - priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); - - IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n", - priv->assoc_id, priv->beacon_int); - - if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE) - priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; - else - priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; - - if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { - if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) - priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; - else - priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) - priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - - } - - iwl4965_commit_rxon(priv); - - switch (priv->iw_mode) { - case IEEE80211_IF_TYPE_STA: - break; - - case IEEE80211_IF_TYPE_IBSS: - - /* assume default assoc id */ - priv->assoc_id = 1; - - iwl_rxon_add_station(priv, priv->bssid, 0); - iwl4965_send_beacon_cmd(priv); - - break; - - default: - IWL_ERROR("%s Should not be called in %d mode\n", - __FUNCTION__, priv->iw_mode); - break; - } - - /* Enable Rx differential gain and sensitivity calibrations */ - iwl_chain_noise_reset(priv); - priv->start_calib = 1; - - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) - priv->assoc_station_added = 1; - - spin_lock_irqsave(&priv->lock, flags); - iwl_activate_qos(priv, 0); - spin_unlock_irqrestore(&priv->lock, flags); - - iwl_power_update_mode(priv, 0); - /* we have just associated, don't start scan too early */ - priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; -} - -static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); - -static void iwl_bg_scan_completed(struct work_struct *work) -{ - struct iwl_priv *priv = - container_of(work, struct iwl_priv, scan_completed); - - IWL_DEBUG_SCAN("SCAN complete scan\n"); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - if (test_bit(STATUS_CONF_PENDING, &priv->status)) - iwl4965_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw)); - - ieee80211_scan_completed(priv->hw); - - /* Since setting the TXPOWER may have been deferred while - * performing the scan, fire one off */ - mutex_lock(&priv->mutex); - iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); - mutex_unlock(&priv->mutex); -} - -/***************************************************************************** - * - * mac80211 entry point functions - * - *****************************************************************************/ - -#define UCODE_READY_TIMEOUT (4 * HZ) - -static int iwl4965_mac_start(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = hw->priv; - int ret; - - IWL_DEBUG_MAC80211("enter\n"); - - if (pci_enable_device(priv->pci_dev)) { - IWL_ERROR("Fail to pci_enable_device\n"); - return -ENODEV; - } - pci_restore_state(priv->pci_dev); - pci_enable_msi(priv->pci_dev); - - ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED, - DRV_NAME, priv); - if (ret) { - IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq); - goto out_disable_msi; - } - - /* we should be verifying the device is ready to be opened */ - mutex_lock(&priv->mutex); - - memset(&priv->staging_rxon, 0, sizeof(struct iwl_rxon_cmd)); - /* fetch ucode file from disk, alloc and copy to bus-master buffers ... - * ucode filename and max sizes are card-specific. */ - - if (!priv->ucode_code.len) { - ret = iwl4965_read_ucode(priv); - if (ret) { - IWL_ERROR("Could not read microcode: %d\n", ret); - mutex_unlock(&priv->mutex); - goto out_release_irq; - } - } - - ret = __iwl4965_up(priv); - - mutex_unlock(&priv->mutex); - - iwl_rfkill_set_hw_state(priv); - - if (ret) - goto out_release_irq; - - IWL_DEBUG_INFO("Start UP work done.\n"); - - if (test_bit(STATUS_IN_SUSPEND, &priv->status)) - return 0; - - /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from - * mac80211 will not be run successfully. */ - ret = wait_event_interruptible_timeout(priv->wait_command_queue, - test_bit(STATUS_READY, &priv->status), - UCODE_READY_TIMEOUT); - if (!ret) { - if (!test_bit(STATUS_READY, &priv->status)) { - IWL_ERROR("START_ALIVE timeout after %dms.\n", - jiffies_to_msecs(UCODE_READY_TIMEOUT)); - ret = -ETIMEDOUT; - goto out_release_irq; - } - } - - priv->is_open = 1; - IWL_DEBUG_MAC80211("leave\n"); - return 0; - -out_release_irq: - free_irq(priv->pci_dev->irq, priv); -out_disable_msi: - pci_disable_msi(priv->pci_dev); - pci_disable_device(priv->pci_dev); - priv->is_open = 0; - IWL_DEBUG_MAC80211("leave - failed\n"); - return ret; -} - -static void iwl4965_mac_stop(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211("enter\n"); - - if (!priv->is_open) { - IWL_DEBUG_MAC80211("leave - skip\n"); - return; - } - - priv->is_open = 0; - - if (iwl_is_ready_rf(priv)) { - /* stop mac, cancel any scan request and clear - * RXON_FILTER_ASSOC_MSK BIT - */ - mutex_lock(&priv->mutex); - iwl_scan_cancel_timeout(priv, 100); - mutex_unlock(&priv->mutex); - } - - iwl4965_down(priv); - - flush_workqueue(priv->workqueue); - free_irq(priv->pci_dev->irq, priv); - pci_disable_msi(priv->pci_dev); - pci_save_state(priv->pci_dev); - pci_disable_device(priv->pci_dev); - - IWL_DEBUG_MAC80211("leave\n"); -} - -static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211("enter\n"); - - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { - IWL_DEBUG_MAC80211("leave - monitor\n"); - dev_kfree_skb_any(skb); - return 0; - } - - IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); - - if (iwl_tx_skb(priv, skb)) - dev_kfree_skb_any(skb); - - IWL_DEBUG_MAC80211("leave\n"); - return 0; -} - -static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_MAC80211("enter: type %d\n", conf->type); - - if (priv->vif) { - IWL_DEBUG_MAC80211("leave - vif != NULL\n"); - return -EOPNOTSUPP; - } - - spin_lock_irqsave(&priv->lock, flags); - priv->vif = conf->vif; - - spin_unlock_irqrestore(&priv->lock, flags); - - mutex_lock(&priv->mutex); - - if (conf->mac_addr) { - IWL_DEBUG_MAC80211("Set %s\n", print_mac(mac, conf->mac_addr)); - memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - } - - if (iwl4965_set_mode(priv, conf->type) == -EAGAIN) - /* we are not ready, will run again when ready */ - set_bit(STATUS_MODE_PENDING, &priv->status); - - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211("leave\n"); - return 0; -} - -/** - * iwl4965_mac_config - mac80211 config callback - * - * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to - * be set inappropriately and the driver currently sets the hardware up to - * use it whenever needed. - */ -static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) -{ - struct iwl_priv *priv = hw->priv; - const struct iwl_channel_info *ch_info; - unsigned long flags; - int ret = 0; - u16 channel; - - mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); - - priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP); - - if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) { - IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n"); - goto out; - } - - if (!conf->radio_enabled) - iwl_radio_kill_sw_disable_radio(priv); - - if (!iwl_is_ready(priv)) { - IWL_DEBUG_MAC80211("leave - not ready\n"); - ret = -EIO; - goto out; - } - - if (unlikely(!priv->cfg->mod_params->disable_hw_scan && - test_bit(STATUS_SCANNING, &priv->status))) { - IWL_DEBUG_MAC80211("leave - scanning\n"); - set_bit(STATUS_CONF_PENDING, &priv->status); - mutex_unlock(&priv->mutex); - return 0; - } - - channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - ch_info = iwl_get_channel_info(priv, conf->channel->band, channel); - if (!is_channel_valid(ch_info)) { - IWL_DEBUG_MAC80211("leave - invalid channel\n"); - ret = -EINVAL; - goto out; - } - - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS && - !is_channel_ibss(ch_info)) { - IWL_ERROR("channel %d in band %d not IBSS channel\n", - conf->channel->hw_value, conf->channel->band); - ret = -EINVAL; - goto out; - } - - spin_lock_irqsave(&priv->lock, flags); - - - /* if we are switching from ht to 2.4 clear flags - * from any ht related info since 2.4 does not - * support ht */ - if ((le16_to_cpu(priv->staging_rxon.channel) != channel) -#ifdef IEEE80211_CONF_CHANNEL_SWITCH - && !(conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) -#endif - ) - priv->staging_rxon.flags = 0; - - iwl_set_rxon_channel(priv, conf->channel->band, channel); - - iwl_set_flags_for_band(priv, conf->channel->band); - - /* The list of supported rates and rate mask can be different - * for each band; since the band may have changed, reset - * the rate mask to what mac80211 lists */ - iwl4965_set_rate(priv); - - spin_unlock_irqrestore(&priv->lock, flags); - -#ifdef IEEE80211_CONF_CHANNEL_SWITCH - if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) { - iwl4965_hw_channel_switch(priv, conf->channel); - goto out; - } -#endif - - if (!conf->radio_enabled) { - IWL_DEBUG_MAC80211("leave - radio disabled\n"); - goto out; - } - - if (iwl_is_rfkill(priv)) { - IWL_DEBUG_MAC80211("leave - RF kill\n"); - ret = -EIO; - goto out; - } - - IWL_DEBUG_MAC80211("TX Power old=%d new=%d\n", - priv->tx_power_user_lmt, conf->power_level); - - iwl_set_tx_power(priv, conf->power_level, false); - - iwl4965_set_rate(priv); - - if (memcmp(&priv->active_rxon, - &priv->staging_rxon, sizeof(priv->staging_rxon))) - iwl4965_commit_rxon(priv); - else - IWL_DEBUG_INFO("No re-sending same RXON configuration.\n"); - - IWL_DEBUG_MAC80211("leave\n"); - -out: - clear_bit(STATUS_CONF_PENDING, &priv->status); - mutex_unlock(&priv->mutex); - return ret; -} - -static void iwl4965_config_ap(struct iwl_priv *priv) -{ - int ret = 0; - unsigned long flags; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - /* The following should be done only at AP bring up */ - if (!(iwl_is_associated(priv))) { - - /* RXON - unassoc (to set timing command) */ - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); - - /* RXON Timing */ - memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd)); - iwl4965_setup_rxon_timing(priv); - ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, - sizeof(priv->rxon_timing), &priv->rxon_timing); - if (ret) - IWL_WARNING("REPLY_RXON_TIMING failed - " - "Attempting to continue.\n"); - - iwl_set_rxon_chain(priv); - - /* FIXME: what should be the assoc_id for AP? */ - priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); - if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE) - priv->staging_rxon.flags |= - RXON_FLG_SHORT_PREAMBLE_MSK; - else - priv->staging_rxon.flags &= - ~RXON_FLG_SHORT_PREAMBLE_MSK; - - if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { - if (priv->assoc_capability & - WLAN_CAPABILITY_SHORT_SLOT_TIME) - priv->staging_rxon.flags |= - RXON_FLG_SHORT_SLOT_MSK; - else - priv->staging_rxon.flags &= - ~RXON_FLG_SHORT_SLOT_MSK; - - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) - priv->staging_rxon.flags &= - ~RXON_FLG_SHORT_SLOT_MSK; - } - /* restore RXON assoc */ - priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); - spin_lock_irqsave(&priv->lock, flags); - iwl_activate_qos(priv, 1); - spin_unlock_irqrestore(&priv->lock, flags); - iwl_rxon_add_station(priv, iwl_bcast_addr, 0); - } - iwl4965_send_beacon_cmd(priv); - - /* FIXME - we need to add code here to detect a totally new - * configuration, reset the AP, unassoc, rxon timing, assoc, - * clear sta table, add BCAST sta... */ -} - -/* temporary */ -static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); - -static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct iwl_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); - unsigned long flags; - int rc; - - if (conf == NULL) - return -EIO; - - if (priv->vif != vif) { - IWL_DEBUG_MAC80211("leave - priv->vif != vif\n"); - return 0; - } - - if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS && - conf->changed & IEEE80211_IFCC_BEACON) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); - if (!beacon) - return -ENOMEM; - rc = iwl4965_mac_beacon_update(hw, beacon); - if (rc) - return rc; - } - - if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && - (!conf->ssid_len)) { - IWL_DEBUG_MAC80211 - ("Leaving in AP mode because HostAPD is not ready.\n"); - return 0; - } - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - mutex_lock(&priv->mutex); - - if (conf->bssid) - IWL_DEBUG_MAC80211("bssid: %s\n", - print_mac(mac, conf->bssid)); - -/* - * very dubious code was here; the probe filtering flag is never set: - * - if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && - !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { - */ - - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { - if (!conf->bssid) { - conf->bssid = priv->mac_addr; - memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); - IWL_DEBUG_MAC80211("bssid was set to: %s\n", - print_mac(mac, conf->bssid)); - } - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - priv->ibss_beacon = ieee80211_beacon_get(hw, vif); - } - - if (iwl_is_rfkill(priv)) - goto done; - - if (conf->bssid && !is_zero_ether_addr(conf->bssid) && - !is_multicast_ether_addr(conf->bssid)) { - /* If there is currently a HW scan going on in the background - * then we need to cancel it else the RXON below will fail. */ - if (iwl_scan_cancel_timeout(priv, 100)) { - IWL_WARNING("Aborted scan still in progress " - "after 100ms\n"); - IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); - mutex_unlock(&priv->mutex); - return -EAGAIN; - } - memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN); - - /* TODO: Audit driver for usage of these members and see - * if mac80211 deprecates them (priv->bssid looks like it - * shouldn't be there, but I haven't scanned the IBSS code - * to verify) - jpk */ - memcpy(priv->bssid, conf->bssid, ETH_ALEN); - - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) - iwl4965_config_ap(priv); - else { - rc = iwl4965_commit_rxon(priv); - if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc) - iwl_rxon_add_station( - priv, priv->active_rxon.bssid_addr, 1); - } - - } else { - iwl_scan_cancel_timeout(priv, 100); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); - } - - done: - spin_lock_irqsave(&priv->lock, flags); - if (!conf->ssid_len) - memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - else - memcpy(priv->essid, conf->ssid, conf->ssid_len); - - priv->essid_len = conf->ssid_len; - spin_unlock_irqrestore(&priv->lock, flags); - - IWL_DEBUG_MAC80211("leave\n"); - mutex_unlock(&priv->mutex); - - return 0; -} - -static void iwl4965_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, struct dev_addr_list *mc_list) -{ - struct iwl_priv *priv = hw->priv; - - if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { - IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", - IEEE80211_IF_TYPE_MNTR, - changed_flags, *total_flags); - /* queue work 'cuz mac80211 is holding a lock which - * prevents us from issuing (synchronous) f/w cmds */ - queue_work(priv->workqueue, &priv->set_monitor); - } - *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | - FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; -} - -static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) -{ - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211("enter\n"); - - mutex_lock(&priv->mutex); - - if (iwl_is_ready_rf(priv)) { - iwl_scan_cancel_timeout(priv, 100); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); - } - if (priv->vif == conf->vif) { - priv->vif = NULL; - memset(priv->bssid, 0, ETH_ALEN); - memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - priv->essid_len = 0; - } - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211("leave\n"); - -} - -#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) -static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changes) -{ - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211("changes = 0x%X\n", changes); - - if (changes & BSS_CHANGED_ERP_PREAMBLE) { - IWL_DEBUG_MAC80211("ERP_PREAMBLE %d\n", - bss_conf->use_short_preamble); - if (bss_conf->use_short_preamble) - priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; - else - priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; - } - - if (changes & BSS_CHANGED_ERP_CTS_PROT) { - IWL_DEBUG_MAC80211("ERP_CTS %d\n", bss_conf->use_cts_prot); - if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ)) - priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK; - else - priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK; - } - - if (changes & BSS_CHANGED_HT) { - IWL_DEBUG_MAC80211("HT %d\n", bss_conf->assoc_ht); - iwl4965_ht_conf(priv, bss_conf); - iwl_set_rxon_chain(priv); - } - - if (changes & BSS_CHANGED_ASSOC) { - IWL_DEBUG_MAC80211("ASSOC %d\n", bss_conf->assoc); - /* This should never happen as this function should - * never be called from interrupt context. */ - if (WARN_ON_ONCE(in_interrupt())) - return; - if (bss_conf->assoc) { - priv->assoc_id = bss_conf->aid; - priv->beacon_int = bss_conf->beacon_int; - priv->power_data.dtim_period = bss_conf->dtim_period; - priv->timestamp = bss_conf->timestamp; - priv->assoc_capability = bss_conf->assoc_capability; - priv->next_scan_jiffies = jiffies + - IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; - mutex_lock(&priv->mutex); - iwl4965_post_associate(priv); - mutex_unlock(&priv->mutex); - } else { - priv->assoc_id = 0; - IWL_DEBUG_MAC80211("DISASSOC %d\n", bss_conf->assoc); - } - } else if (changes && iwl_is_associated(priv) && priv->assoc_id) { - IWL_DEBUG_MAC80211("Associated Changes %d\n", changes); - iwl_send_rxon_assoc(priv); - } - -} - -static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) -{ - int rc = 0; - unsigned long flags; - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211("enter\n"); - - mutex_lock(&priv->mutex); - spin_lock_irqsave(&priv->lock, flags); - - if (!iwl_is_ready_rf(priv)) { - rc = -EIO; - IWL_DEBUG_MAC80211("leave - not ready or exit pending\n"); - goto out_unlock; - } - - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */ - rc = -EIO; - IWL_ERROR("ERROR: APs don't scan\n"); - goto out_unlock; - } - - /* we don't schedule scan within next_scan_jiffies period */ - if (priv->next_scan_jiffies && - time_after(priv->next_scan_jiffies, jiffies)) { - rc = -EAGAIN; - goto out_unlock; - } - /* if we just finished scan ask for delay */ - if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies + - IWL_DELAY_NEXT_SCAN, jiffies)) { - rc = -EAGAIN; - goto out_unlock; - } - if (len) { - IWL_DEBUG_SCAN("direct scan for %s [%d]\n ", - iwl_escape_essid(ssid, len), (int)len); - - priv->one_direct_scan = 1; - priv->direct_ssid_len = (u8) - min((u8) len, (u8) IW_ESSID_MAX_SIZE); - memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); - } else - priv->one_direct_scan = 0; - - rc = iwl_scan_initiate(priv); - - IWL_DEBUG_MAC80211("leave\n"); - -out_unlock: - spin_unlock_irqrestore(&priv->lock, flags); - mutex_unlock(&priv->mutex); - - return rc; -} - -static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw, - struct ieee80211_key_conf *keyconf, const u8 *addr, - u32 iv32, u16 *phase1key) -{ - struct iwl_priv *priv = hw->priv; - u8 sta_id = IWL_INVALID_STATION; - unsigned long flags; - __le16 key_flags = 0; - int i; - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_MAC80211("enter\n"); - - sta_id = iwl_find_station(priv, addr); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_MAC80211("leave - %s not in station map.\n", - print_mac(mac, addr)); - return; - } - - iwl_scan_cancel_timeout(priv, 100); - - key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK); - key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); - key_flags &= ~STA_KEY_FLG_INVALID; - - if (sta_id == priv->hw_params.bcast_sta_id) - key_flags |= STA_KEY_MULTICAST_MSK; - - spin_lock_irqsave(&priv->sta_lock, flags); - - priv->stations[sta_id].sta.key.key_flags = key_flags; - priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32; - - for (i = 0; i < 5; i++) - priv->stations[sta_id].sta.key.tkip_rx_ttak[i] = - cpu_to_le16(phase1key[i]); - - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - - iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); - - spin_unlock_irqrestore(&priv->sta_lock, flags); - - IWL_DEBUG_MAC80211("leave\n"); -} - -static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - const u8 *local_addr, const u8 *addr, - struct ieee80211_key_conf *key) -{ - struct iwl_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); - int ret = 0; - u8 sta_id = IWL_INVALID_STATION; - u8 is_default_wep_key = 0; - - IWL_DEBUG_MAC80211("enter\n"); - - if (priv->hw_params.sw_crypto) { - IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n"); - return -EOPNOTSUPP; - } - - if (is_zero_ether_addr(addr)) - /* only support pairwise keys */ - return -EOPNOTSUPP; - - sta_id = iwl_find_station(priv, addr); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_MAC80211("leave - %s not in station map.\n", - print_mac(mac, addr)); - return -EINVAL; - - } - - mutex_lock(&priv->mutex); - iwl_scan_cancel_timeout(priv, 100); - mutex_unlock(&priv->mutex); - - /* If we are getting WEP group key and we didn't receive any key mapping - * so far, we are in legacy wep mode (group key only), otherwise we are - * in 1X mode. - * In legacy wep mode, we use another host command to the uCode */ - if (key->alg == ALG_WEP && sta_id == priv->hw_params.bcast_sta_id && - priv->iw_mode != IEEE80211_IF_TYPE_AP) { - if (cmd == SET_KEY) - is_default_wep_key = !priv->key_mapping_key; - else - is_default_wep_key = - (key->hw_key_idx == HW_KEY_DEFAULT); - } - - switch (cmd) { - case SET_KEY: - if (is_default_wep_key) - ret = iwl_set_default_wep_key(priv, key); - else - ret = iwl_set_dynamic_key(priv, key, sta_id); - - IWL_DEBUG_MAC80211("enable hwcrypto key\n"); - break; - case DISABLE_KEY: - if (is_default_wep_key) - ret = iwl_remove_default_wep_key(priv, key); - else - ret = iwl_remove_dynamic_key(priv, key, sta_id); - - IWL_DEBUG_MAC80211("disable hwcrypto key\n"); - break; - default: - ret = -EINVAL; - } - - IWL_DEBUG_MAC80211("leave\n"); - - return ret; -} - -static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *params) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - int q; - - IWL_DEBUG_MAC80211("enter\n"); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211("leave - RF not ready\n"); - return -EIO; - } - - if (queue >= AC_NUM) { - IWL_DEBUG_MAC80211("leave - queue >= AC_NUM %d\n", queue); - return 0; - } - - if (!priv->qos_data.qos_enable) { - priv->qos_data.qos_active = 0; - IWL_DEBUG_MAC80211("leave - qos not enabled\n"); - return 0; - } - q = AC_NUM - 1 - queue; - - spin_lock_irqsave(&priv->lock, flags); - - priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min); - priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); - priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; - priv->qos_data.def_qos_parm.ac[q].edca_txop = - cpu_to_le16((params->txop * 32)); - - priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; - priv->qos_data.qos_active = 1; - - if (priv->iw_mode == IEEE80211_IF_TYPE_AP) - iwl_activate_qos(priv, 1); - else if (priv->assoc_id && iwl_is_associated(priv)) - iwl_activate_qos(priv, 0); - - spin_unlock_irqrestore(&priv->lock, flags); - - IWL_DEBUG_MAC80211("leave\n"); - return 0; -} - -static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, - enum ieee80211_ampdu_mlme_action action, - const u8 *addr, u16 tid, u16 *ssn) -{ - struct iwl_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n", - print_mac(mac, addr), tid); - - if (!(priv->cfg->sku & IWL_SKU_N)) - return -EACCES; - - switch (action) { - case IEEE80211_AMPDU_RX_START: - IWL_DEBUG_HT("start Rx\n"); - return iwl_rx_agg_start(priv, addr, tid, *ssn); - case IEEE80211_AMPDU_RX_STOP: - IWL_DEBUG_HT("stop Rx\n"); - return iwl_rx_agg_stop(priv, addr, tid); - case IEEE80211_AMPDU_TX_START: - IWL_DEBUG_HT("start Tx\n"); - return iwl_tx_agg_start(priv, addr, tid, ssn); - case IEEE80211_AMPDU_TX_STOP: - IWL_DEBUG_HT("stop Tx\n"); - return iwl_tx_agg_stop(priv, addr, tid); - default: - IWL_DEBUG_HT("unknown\n"); - return -EINVAL; - break; - } - return 0; -} -static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, - struct ieee80211_tx_queue_stats *stats) -{ - struct iwl_priv *priv = hw->priv; - int i, avail; - struct iwl_tx_queue *txq; - struct iwl_queue *q; - unsigned long flags; - - IWL_DEBUG_MAC80211("enter\n"); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211("leave - RF not ready\n"); - return -EIO; - } - - spin_lock_irqsave(&priv->lock, flags); - - for (i = 0; i < AC_NUM; i++) { - txq = &priv->txq[i]; - q = &txq->q; - avail = iwl_queue_space(q); - - stats[i].len = q->n_window - avail; - stats[i].limit = q->n_window - q->high_mark; - stats[i].count = q->n_window; - - } - spin_unlock_irqrestore(&priv->lock, flags); - - IWL_DEBUG_MAC80211("leave\n"); - - return 0; -} - -static int iwl4965_mac_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats) -{ - struct iwl_priv *priv = hw->priv; - - priv = hw->priv; - IWL_DEBUG_MAC80211("enter\n"); - IWL_DEBUG_MAC80211("leave\n"); - - return 0; -} - -static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - - mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211("enter\n"); - - spin_lock_irqsave(&priv->lock, flags); - memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info)); - spin_unlock_irqrestore(&priv->lock, flags); - - iwl_reset_qos(priv); - - spin_lock_irqsave(&priv->lock, flags); - priv->assoc_id = 0; - priv->assoc_capability = 0; - priv->assoc_station_added = 0; - - /* new association get rid of ibss beacon skb */ - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - priv->ibss_beacon = NULL; - - priv->beacon_int = priv->hw->conf.beacon_int; - priv->timestamp = 0; - if ((priv->iw_mode == IEEE80211_IF_TYPE_STA)) - priv->beacon_int = 0; - - spin_unlock_irqrestore(&priv->lock, flags); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211("leave - not ready\n"); - mutex_unlock(&priv->mutex); - return; - } - - /* we are restarting association process - * clear RXON_FILTER_ASSOC_MSK bit - */ - if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { - iwl_scan_cancel_timeout(priv, 100); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); - } - - iwl_power_update_mode(priv, 0); - - /* Per mac80211.h: This is only used in IBSS mode... */ - if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { - - IWL_DEBUG_MAC80211("leave - not in IBSS\n"); - mutex_unlock(&priv->mutex); - return; - } - - iwl4965_set_rate(priv); - - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211("leave\n"); -} - -static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - __le64 timestamp; - - mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211("enter\n"); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211("leave - RF not ready\n"); - mutex_unlock(&priv->mutex); - return -EIO; - } - - if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { - IWL_DEBUG_MAC80211("leave - not IBSS\n"); - mutex_unlock(&priv->mutex); - return -EIO; - } - - spin_lock_irqsave(&priv->lock, flags); - - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - priv->ibss_beacon = skb; - - priv->assoc_id = 0; - timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; - priv->timestamp = le64_to_cpu(timestamp) + (priv->beacon_int * 1000); - - IWL_DEBUG_MAC80211("leave\n"); - spin_unlock_irqrestore(&priv->lock, flags); - - iwl_reset_qos(priv); - - iwl4965_post_associate(priv); - - mutex_unlock(&priv->mutex); - - return 0; -} - -/***************************************************************************** - * - * sysfs attributes - * - *****************************************************************************/ - -#ifdef CONFIG_IWLWIFI_DEBUG - -/* - * The following adds a new attribute to the sysfs representation - * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/) - * used for controlling the debug level. - * - * See the level definitions in iwl for details. - */ - -static ssize_t show_debug_level(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = d->driver_data; - - return sprintf(buf, "0x%08X\n", priv->debug_level); -} -static ssize_t store_debug_level(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = d->driver_data; - char *p = (char *)buf; - u32 val; - - val = simple_strtoul(p, &p, 0); - if (p == buf) - printk(KERN_INFO DRV_NAME - ": %s is not in hex or decimal form.\n", buf); - else - priv->debug_level = val; - - return strnlen(buf, count); -} - -static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, - show_debug_level, store_debug_level); - - -#endif /* CONFIG_IWLWIFI_DEBUG */ - - -static ssize_t show_version(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = d->driver_data; - struct iwl_alive_resp *palive = &priv->card_alive; - ssize_t pos = 0; - u16 eeprom_ver; - - if (palive->is_valid) - pos += sprintf(buf + pos, - "fw version: 0x%01X.0x%01X.0x%01X.0x%01X\n" - "fw type: 0x%01X 0x%01X\n", - palive->ucode_major, palive->ucode_minor, - palive->sw_rev[0], palive->sw_rev[1], - palive->ver_type, palive->ver_subtype); - else - pos += sprintf(buf + pos, "fw not loaded\n"); - - if (priv->eeprom) { - eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - pos += sprintf(buf + pos, "EEPROM version: 0x%x\n", - eeprom_ver); - } else { - pos += sprintf(buf + pos, "EEPROM not initialzed\n"); - } - - return pos; -} - -static DEVICE_ATTR(version, S_IWUSR | S_IRUGO, show_version, NULL); - -static ssize_t show_temperature(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - return sprintf(buf, "%d\n", priv->temperature); -} - -static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); - -static ssize_t show_tx_power(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - return sprintf(buf, "%d\n", priv->tx_power_user_lmt); -} - -static ssize_t store_tx_power(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - char *p = (char *)buf; - u32 val; - - val = simple_strtoul(p, &p, 10); - if (p == buf) - printk(KERN_INFO DRV_NAME - ": %s is not in decimal form.\n", buf); - else - iwl_set_tx_power(priv, val, false); - - return count; -} - -static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); - -static ssize_t show_flags(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - - return sprintf(buf, "0x%04X\n", priv->active_rxon.flags); -} - -static ssize_t store_flags(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - u32 flags = simple_strtoul(buf, NULL, 0); - - mutex_lock(&priv->mutex); - if (le32_to_cpu(priv->staging_rxon.flags) != flags) { - /* Cancel any currently running scans... */ - if (iwl_scan_cancel_timeout(priv, 100)) - IWL_WARNING("Could not cancel scan.\n"); - else { - IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n", - flags); - priv->staging_rxon.flags = cpu_to_le32(flags); - iwl4965_commit_rxon(priv); - } - } - mutex_unlock(&priv->mutex); - - return count; -} - -static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags); - -static ssize_t show_filter_flags(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - - return sprintf(buf, "0x%04X\n", - le32_to_cpu(priv->active_rxon.filter_flags)); -} - -static ssize_t store_filter_flags(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - u32 filter_flags = simple_strtoul(buf, NULL, 0); - - mutex_lock(&priv->mutex); - if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) { - /* Cancel any currently running scans... */ - if (iwl_scan_cancel_timeout(priv, 100)) - IWL_WARNING("Could not cancel scan.\n"); - else { - IWL_DEBUG_INFO("Committing rxon.filter_flags = " - "0x%04X\n", filter_flags); - priv->staging_rxon.filter_flags = - cpu_to_le32(filter_flags); - iwl4965_commit_rxon(priv); - } - } - mutex_unlock(&priv->mutex); - - return count; -} - -static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, - store_filter_flags); - -#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT - -static ssize_t show_measurement(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - struct iwl4965_spectrum_notification measure_report; - u32 size = sizeof(measure_report), len = 0, ofs = 0; - u8 *data = (u8 *) & measure_report; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - if (!(priv->measurement_status & MEASUREMENT_READY)) { - spin_unlock_irqrestore(&priv->lock, flags); - return 0; - } - memcpy(&measure_report, &priv->measure_report, size); - priv->measurement_status = 0; - spin_unlock_irqrestore(&priv->lock, flags); - - while (size && (PAGE_SIZE - len)) { - hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, - PAGE_SIZE - len, 1); - len = strlen(buf); - if (PAGE_SIZE - len) - buf[len++] = '\n'; - - ofs += 16; - size -= min(size, 16U); - } - - return len; -} - -static ssize_t store_measurement(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - struct ieee80211_measurement_params params = { - .channel = le16_to_cpu(priv->active_rxon.channel), - .start_time = cpu_to_le64(priv->last_tsf), - .duration = cpu_to_le16(1), - }; - u8 type = IWL_MEASURE_BASIC; - u8 buffer[32]; - u8 channel; - - if (count) { - char *p = buffer; - strncpy(buffer, buf, min(sizeof(buffer), count)); - channel = simple_strtoul(p, NULL, 0); - if (channel) - params.channel = channel; - - p = buffer; - while (*p && *p != ' ') - p++; - if (*p) - type = simple_strtoul(p + 1, NULL, 0); - } - - IWL_DEBUG_INFO("Invoking measurement of type %d on " - "channel %d (for '%s')\n", type, params.channel, buf); - iwl4965_get_measurement(priv, ¶ms, type); - - return count; -} - -static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, - show_measurement, store_measurement); -#endif /* CONFIG_IWL4965_SPECTRUM_MEASUREMENT */ - -static ssize_t store_retry_rate(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - - priv->retry_rate = simple_strtoul(buf, NULL, 0); - if (priv->retry_rate <= 0) - priv->retry_rate = 1; - - return count; -} - -static ssize_t show_retry_rate(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - return sprintf(buf, "%d", priv->retry_rate); -} - -static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate, - store_retry_rate); - -static ssize_t store_power_level(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - int ret; - int mode; - - mode = simple_strtoul(buf, NULL, 0); - mutex_lock(&priv->mutex); - - if (!iwl_is_ready(priv)) { - ret = -EAGAIN; - goto out; - } - - ret = iwl_power_set_user_mode(priv, mode); - if (ret) { - IWL_DEBUG_MAC80211("failed setting power mode.\n"); - goto out; - } - ret = count; - - out: - mutex_unlock(&priv->mutex); - return ret; -} - -static ssize_t show_power_level(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - int mode = priv->power_data.user_power_setting; - int system = priv->power_data.system_power_setting; - int level = priv->power_data.power_mode; - char *p = buf; - - switch (system) { - case IWL_POWER_SYS_AUTO: - p += sprintf(p, "SYSTEM:auto"); - break; - case IWL_POWER_SYS_AC: - p += sprintf(p, "SYSTEM:ac"); - break; - case IWL_POWER_SYS_BATTERY: - p += sprintf(p, "SYSTEM:battery"); - break; - } - - p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO)?"fixed":"auto"); - p += sprintf(p, "\tINDEX:%d", level); - p += sprintf(p, "\n"); - return (p - buf + 1); -} - -static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, - store_power_level); - -static ssize_t show_channels(struct device *d, - struct device_attribute *attr, char *buf) -{ - - struct iwl_priv *priv = dev_get_drvdata(d); - struct ieee80211_channel *channels = NULL; - const struct ieee80211_supported_band *supp_band = NULL; - int len = 0, i; - int count = 0; - - if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status)) - return -EAGAIN; - - supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ); - channels = supp_band->channels; - count = supp_band->n_channels; - - len += sprintf(&buf[len], - "Displaying %d channels in 2.4GHz band " - "(802.11bg):\n", count); - - for (i = 0; i < count; i++) - len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", - ieee80211_frequency_to_channel( - channels[i].center_freq), - channels[i].max_power, - channels[i].flags & IEEE80211_CHAN_RADAR ? - " (IEEE 802.11h required)" : "", - (!(channels[i].flags & IEEE80211_CHAN_NO_IBSS) - || (channels[i].flags & - IEEE80211_CHAN_RADAR)) ? "" : - ", IBSS", - channels[i].flags & - IEEE80211_CHAN_PASSIVE_SCAN ? - "passive only" : "active/passive"); - - supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ); - channels = supp_band->channels; - count = supp_band->n_channels; - - len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band " - "(802.11a):\n", count); - - for (i = 0; i < count; i++) - len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", - ieee80211_frequency_to_channel( - channels[i].center_freq), - channels[i].max_power, - channels[i].flags & IEEE80211_CHAN_RADAR ? - " (IEEE 802.11h required)" : "", - ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) - || (channels[i].flags & - IEEE80211_CHAN_RADAR)) ? "" : - ", IBSS", - channels[i].flags & - IEEE80211_CHAN_PASSIVE_SCAN ? - "passive only" : "active/passive"); - - return len; -} - -static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); - -static ssize_t show_statistics(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - u32 size = sizeof(struct iwl_notif_statistics); - u32 len = 0, ofs = 0; - u8 *data = (u8 *) & priv->statistics; - int rc = 0; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - mutex_lock(&priv->mutex); - rc = iwl_send_statistics_request(priv, 0); - mutex_unlock(&priv->mutex); - - if (rc) { - len = sprintf(buf, - "Error sending statistics request: 0x%08X\n", rc); - return len; - } - - while (size && (PAGE_SIZE - len)) { - hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, - PAGE_SIZE - len, 1); - len = strlen(buf); - if (PAGE_SIZE - len) - buf[len++] = '\n'; - - ofs += 16; - size -= min(size, 16U); - } - - return len; -} - -static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL); - -static ssize_t show_status(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - if (!iwl_is_alive(priv)) - return -EAGAIN; - return sprintf(buf, "0x%08x\n", (int)priv->status); -} - -static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); - -/***************************************************************************** - * - * driver setup and teardown - * - *****************************************************************************/ - -static void iwl_setup_deferred_work(struct iwl_priv *priv) -{ - priv->workqueue = create_workqueue(DRV_NAME); - - init_waitqueue_head(&priv->wait_command_queue); - - INIT_WORK(&priv->up, iwl4965_bg_up); - INIT_WORK(&priv->restart, iwl4965_bg_restart); - INIT_WORK(&priv->rx_replenish, iwl4965_bg_rx_replenish); - INIT_WORK(&priv->rf_kill, iwl4965_bg_rf_kill); - INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update); - INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor); - INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); - INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); - INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); - - /* FIXME : remove when resolved PENDING */ - INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); - iwl_setup_scan_deferred_work(priv); - - if (priv->cfg->ops->lib->setup_deferred_work) - priv->cfg->ops->lib->setup_deferred_work(priv); - - init_timer(&priv->statistics_periodic); - priv->statistics_periodic.data = (unsigned long)priv; - priv->statistics_periodic.function = iwl4965_bg_statistics_periodic; - - tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl4965_irq_tasklet, (unsigned long)priv); -} - -static void iwl_cancel_deferred_work(struct iwl_priv *priv) -{ - if (priv->cfg->ops->lib->cancel_deferred_work) - priv->cfg->ops->lib->cancel_deferred_work(priv); - - cancel_delayed_work_sync(&priv->init_alive_start); - cancel_delayed_work(&priv->scan_check); - cancel_delayed_work(&priv->alive_start); - cancel_work_sync(&priv->beacon_update); - del_timer_sync(&priv->statistics_periodic); -} - -static struct attribute *iwl4965_sysfs_entries[] = { - &dev_attr_channels.attr, - &dev_attr_flags.attr, - &dev_attr_filter_flags.attr, -#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT - &dev_attr_measurement.attr, -#endif - &dev_attr_power_level.attr, - &dev_attr_retry_rate.attr, - &dev_attr_statistics.attr, - &dev_attr_status.attr, - &dev_attr_temperature.attr, - &dev_attr_tx_power.attr, -#ifdef CONFIG_IWLWIFI_DEBUG - &dev_attr_debug_level.attr, -#endif - &dev_attr_version.attr, - - NULL -}; - -static struct attribute_group iwl4965_attribute_group = { - .name = NULL, /* put in device directory */ - .attrs = iwl4965_sysfs_entries, -}; - -static struct ieee80211_ops iwl4965_hw_ops = { - .tx = iwl4965_mac_tx, - .start = iwl4965_mac_start, - .stop = iwl4965_mac_stop, - .add_interface = iwl4965_mac_add_interface, - .remove_interface = iwl4965_mac_remove_interface, - .config = iwl4965_mac_config, - .config_interface = iwl4965_mac_config_interface, - .configure_filter = iwl4965_configure_filter, - .set_key = iwl4965_mac_set_key, - .update_tkip_key = iwl4965_mac_update_tkip_key, - .get_stats = iwl4965_mac_get_stats, - .get_tx_stats = iwl4965_mac_get_tx_stats, - .conf_tx = iwl4965_mac_conf_tx, - .reset_tsf = iwl4965_mac_reset_tsf, - .bss_info_changed = iwl4965_bss_info_changed, - .ampdu_action = iwl4965_mac_ampdu_action, - .hw_scan = iwl4965_mac_hw_scan -}; - -static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int err = 0; - struct iwl_priv *priv; - struct ieee80211_hw *hw; - struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); - unsigned long flags; - DECLARE_MAC_BUF(mac); - - /************************ - * 1. Allocating HW data - ************************/ - - /* Disabling hardware scan means that mac80211 will perform scans - * "the hard way", rather than using device's scan. */ - if (cfg->mod_params->disable_hw_scan) { - if (cfg->mod_params->debug & IWL_DL_INFO) - dev_printk(KERN_DEBUG, &(pdev->dev), - "Disabling hw_scan\n"); - iwl4965_hw_ops.hw_scan = NULL; - } - - hw = iwl_alloc_all(cfg, &iwl4965_hw_ops); - if (!hw) { - err = -ENOMEM; - goto out; - } - priv = hw->priv; - /* At this point both hw and priv are allocated. */ - - SET_IEEE80211_DEV(hw, &pdev->dev); - - IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); - priv->cfg = cfg; - priv->pci_dev = pdev; - -#ifdef CONFIG_IWLWIFI_DEBUG - priv->debug_level = priv->cfg->mod_params->debug; - atomic_set(&priv->restrict_refcnt, 0); -#endif - - /************************** - * 2. Initializing PCI bus - **************************/ - if (pci_enable_device(pdev)) { - err = -ENODEV; - goto out_ieee80211_free_hw; - } - - pci_set_master(pdev); - - err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); - if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); - if (err) { - err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); - if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); - /* both attempts failed: */ - if (err) { - printk(KERN_WARNING "%s: No suitable DMA available.\n", - DRV_NAME); - goto out_pci_disable_device; - } - } - - err = pci_request_regions(pdev, DRV_NAME); - if (err) - goto out_pci_disable_device; - - pci_set_drvdata(pdev, priv); - - /* We disable the RETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state */ - pci_write_config_byte(pdev, 0x41, 0x00); - - /*********************** - * 3. Read REV register - ***********************/ - priv->hw_base = pci_iomap(pdev, 0, 0); - if (!priv->hw_base) { - err = -ENODEV; - goto out_pci_release_regions; - } - - IWL_DEBUG_INFO("pci_resource_len = 0x%08llx\n", - (unsigned long long) pci_resource_len(pdev, 0)); - IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base); - - iwl_hw_detect(priv); - printk(KERN_INFO DRV_NAME - ": Detected Intel Wireless WiFi Link %s REV=0x%X\n", - priv->cfg->name, priv->hw_rev); - - /* amp init */ - err = priv->cfg->ops->lib->apm_ops.init(priv); - if (err < 0) { - IWL_DEBUG_INFO("Failed to init APMG\n"); - goto out_iounmap; - } - /***************** - * 4. Read EEPROM - *****************/ - /* Read the EEPROM */ - err = iwl_eeprom_init(priv); - if (err) { - IWL_ERROR("Unable to init EEPROM\n"); - goto out_iounmap; - } - err = iwl_eeprom_check_version(priv); - if (err) - goto out_iounmap; - - /* extract MAC Address */ - iwl_eeprom_get_mac(priv, priv->mac_addr); - IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr)); - SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); - - /************************ - * 5. Setup HW constants - ************************/ - if (iwl_set_hw_params(priv)) { - IWL_ERROR("failed to set hw parameters\n"); - goto out_free_eeprom; - } - - /******************* - * 6. Setup priv - *******************/ - - err = iwl_init_drv(priv); - if (err) - goto out_free_eeprom; - /* At this point both hw and priv are initialized. */ - - /********************************** - * 7. Initialize module parameters - **********************************/ - - /* Disable radio (SW RF KILL) via parameter when loading driver */ - if (priv->cfg->mod_params->disable) { - set_bit(STATUS_RF_KILL_SW, &priv->status); - IWL_DEBUG_INFO("Radio disabled.\n"); - } - - /******************** - * 8. Setup services - ********************/ - spin_lock_irqsave(&priv->lock, flags); - iwl4965_disable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group); - if (err) { - IWL_ERROR("failed to create sysfs device attributes\n"); - goto out_uninit_drv; - } - - - iwl_setup_deferred_work(priv); - iwl_setup_rx_handlers(priv); - - /******************** - * 9. Conclude - ********************/ - pci_save_state(pdev); - pci_disable_device(pdev); - - /********************************** - * 10. Setup and register mac80211 - **********************************/ - - err = iwl_setup_mac(priv); - if (err) - goto out_remove_sysfs; - - err = iwl_dbgfs_register(priv, DRV_NAME); - if (err) - IWL_ERROR("failed to create debugfs files\n"); - - err = iwl_rfkill_init(priv); - if (err) - IWL_ERROR("Unable to initialize RFKILL system. " - "Ignoring error: %d\n", err); - iwl_power_initialize(priv); - return 0; - - out_remove_sysfs: - sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); - out_uninit_drv: - iwl_uninit_drv(priv); - out_free_eeprom: - iwl_eeprom_free(priv); - out_iounmap: - pci_iounmap(pdev, priv->hw_base); - out_pci_release_regions: - pci_release_regions(pdev); - pci_set_drvdata(pdev, NULL); - out_pci_disable_device: - pci_disable_device(pdev); - out_ieee80211_free_hw: - ieee80211_free_hw(priv->hw); - out: - return err; -} - -static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) -{ - struct iwl_priv *priv = pci_get_drvdata(pdev); - unsigned long flags; - - if (!priv) - return; - - IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n"); - - iwl_dbgfs_unregister(priv); - sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); - - if (priv->mac80211_registered) { - ieee80211_unregister_hw(priv->hw); - priv->mac80211_registered = 0; - } - - set_bit(STATUS_EXIT_PENDING, &priv->status); - - iwl4965_down(priv); - - /* make sure we flush any pending irq or - * tasklet for the driver - */ - spin_lock_irqsave(&priv->lock, flags); - iwl4965_disable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - iwl_synchronize_irq(priv); - - iwl_rfkill_unregister(priv); - iwl4965_dealloc_ucode_pci(priv); - - if (priv->rxq.bd) - iwl_rx_queue_free(priv, &priv->rxq); - iwl_hw_txq_ctx_free(priv); - - iwl_clear_stations_table(priv); - iwl_eeprom_free(priv); - - - /*netif_stop_queue(dev); */ - flush_workqueue(priv->workqueue); - - /* ieee80211_unregister_hw calls iwl4965_mac_stop, which flushes - * priv->workqueue... so we can't take down the workqueue - * until now... */ - destroy_workqueue(priv->workqueue); - priv->workqueue = NULL; - - pci_iounmap(pdev, priv->hw_base); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - - iwl_uninit_drv(priv); - - if (priv->ibss_beacon) - dev_kfree_skb(priv->ibss_beacon); - - ieee80211_free_hw(priv->hw); -} - -#ifdef CONFIG_PM - -static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct iwl_priv *priv = pci_get_drvdata(pdev); - - if (priv->is_open) { - set_bit(STATUS_IN_SUSPEND, &priv->status); - iwl4965_mac_stop(priv->hw); - priv->is_open = 1; - } - - pci_set_power_state(pdev, PCI_D3hot); - - return 0; -} - -static int iwl4965_pci_resume(struct pci_dev *pdev) -{ - struct iwl_priv *priv = pci_get_drvdata(pdev); - - pci_set_power_state(pdev, PCI_D0); - - if (priv->is_open) - iwl4965_mac_start(priv->hw); - - clear_bit(STATUS_IN_SUSPEND, &priv->status); - return 0; -} - -#endif /* CONFIG_PM */ - -/***************************************************************************** - * - * driver and module entry point - * - *****************************************************************************/ - -/* Hardware specific file defines the PCI IDs table for that hardware module */ -static struct pci_device_id iwl_hw_card_ids[] = { - {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)}, - {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)}, -#ifdef CONFIG_IWL5000 - {IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bg_cfg)}, - {IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bg_cfg)}, - {IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)}, - {IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)}, - {IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)}, - {IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)}, - {IWL_PCI_DEVICE(0x4232, PCI_ANY_ID, iwl5100_agn_cfg)}, - {IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)}, - {IWL_PCI_DEVICE(0x4236, PCI_ANY_ID, iwl5300_agn_cfg)}, - {IWL_PCI_DEVICE(0x4237, PCI_ANY_ID, iwl5100_agn_cfg)}, - {IWL_PCI_DEVICE(0x423A, PCI_ANY_ID, iwl5350_agn_cfg)}, -#endif /* CONFIG_IWL5000 */ - {0} -}; -MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); - -static struct pci_driver iwl_driver = { - .name = DRV_NAME, - .id_table = iwl_hw_card_ids, - .probe = iwl4965_pci_probe, - .remove = __devexit_p(iwl4965_pci_remove), -#ifdef CONFIG_PM - .suspend = iwl4965_pci_suspend, - .resume = iwl4965_pci_resume, -#endif -}; - -static int __init iwl4965_init(void) -{ - - int ret; - printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); - printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); - - ret = iwlagn_rate_control_register(); - if (ret) { - IWL_ERROR("Unable to register rate control algorithm: %d\n", ret); - return ret; - } - - ret = pci_register_driver(&iwl_driver); - if (ret) { - IWL_ERROR("Unable to initialize PCI module\n"); - goto error_register; - } - - return ret; - -error_register: - iwlagn_rate_control_unregister(); - return ret; -} - -static void __exit iwl4965_exit(void) -{ - pci_unregister_driver(&iwl_driver); - iwlagn_rate_control_unregister(); -} - -module_exit(iwl4965_exit); -module_init(iwl4965_init); -- cgit v1.2.3 From 3ac7f14694dd38273d9d96f1c873233d71190c15 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 21 Jul 2008 02:40:14 +0300 Subject: iwlwifi: fix checkpatch.pl errors This patch fixes errors reported by checkpatch in iwlwifi drivers Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 7 ++-- drivers/net/wireless/iwlwifi/iwl-4965.c | 4 +-- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 16 ++++----- drivers/net/wireless/iwlwifi/iwl-agn.c | 10 +++--- drivers/net/wireless/iwlwifi/iwl-core.c | 4 +-- drivers/net/wireless/iwlwifi/iwl-debug.h | 4 +-- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 11 +++--- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 3 +- drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 52 +++++++++++++---------------- 11 files changed, 55 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 56a9361a847..b3931f6135a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -795,8 +795,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)header; __le32 *pos; - pos = - (__le32 *) & mgmt->u.beacon. + pos = (__le32 *)&mgmt->u.beacon. timestamp; priv->timestamp0 = le32_to_cpu(pos[0]); priv->timestamp1 = le32_to_cpu(pos[1]); @@ -1509,7 +1508,7 @@ static int iwl3945_hw_reg_adjust_power_by_temp(int new_reading, int old_reading) */ static inline int iwl3945_hw_reg_temp_out_of_range(int temperature) { - return (((temperature < -260) || (temperature > 25)) ? 1 : 0); + return ((temperature < -260) || (temperature > 25)) ? 1 : 0; } int iwl3945_hw_get_temperature(struct iwl3945_priv *priv) @@ -2630,7 +2629,7 @@ unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv, tx_beacon_cmd->tx.supp_rates[1] = (IWL_CCK_BASIC_RATES_MASK & 0xF); - return (sizeof(struct iwl3945_tx_beacon_cmd) + frame_size); + return sizeof(struct iwl3945_tx_beacon_cmd) + frame_size; } void iwl3945_hw_rx_handler_setup(struct iwl3945_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index f356f4f0944..718f9d9e494 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1515,11 +1515,11 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, c, atten_value, power_index, tx_power.s.radio_tx_gain[c], tx_power.s.dsp_predis_atten[c]); - }/* for each chain */ + } /* for each chain */ tx_power_tbl->power_tbl[i].dw = cpu_to_le32(tx_power.dw); - }/* for each rate */ + } /* for each rate */ return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 076d3560302..f7bbd12193f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1131,7 +1131,7 @@ static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask) static inline u32 iwl5000_get_scd_ssn(struct iwl5000_tx_resp *tx_resp) { - return le32_to_cpup((__le32*)&tx_resp->status + + return le32_to_cpup((__le32 *)&tx_resp->status + tx_resp->frame_count) & MAX_SN; } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index b498b58d81f..754fef5b592 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -245,7 +245,7 @@ static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type) { - return ((ant_type & valid_antenna) == ant_type); + return (ant_type & valid_antenna) == ant_type; } /* @@ -384,9 +384,9 @@ static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid, static inline int get_num_of_ant_from_rate(u32 rate_n_flags) { - return (!!(rate_n_flags & RATE_MCS_ANT_A_MSK) + - !!(rate_n_flags & RATE_MCS_ANT_B_MSK) + - !!(rate_n_flags & RATE_MCS_ANT_C_MSK)); + return !!(rate_n_flags & RATE_MCS_ANT_A_MSK) + + !!(rate_n_flags & RATE_MCS_ANT_B_MSK) + + !!(rate_n_flags & RATE_MCS_ANT_C_MSK); } /** @@ -620,9 +620,9 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, #if 0 static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf) { - return ((conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && + return (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && priv->current_ht_config.is_green_field && - !priv->current_ht_config.non_GF_STA_present); + !priv->current_ht_config.non_GF_STA_present; } #endif static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf) @@ -2157,7 +2157,7 @@ static void *rs_alloc_sta(void *priv_rate, gfp_t gfp) for (j = 0; j < LQ_SIZE; j++) for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i])); + rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); return lq_sta; } @@ -2179,7 +2179,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, sta->txrate_idx = 3; for (j = 0; j < LQ_SIZE; j++) for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i])); + rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); IWL_DEBUG_RATE("LQ: *** rate scale global init ***\n"); /* TODO: what is a good starting rate for STA? About middle? Maybe not diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index f71b3f3f81b..4ff0636dbdd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2476,7 +2476,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) unsigned long flags; if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { - IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__); + IWL_ERROR("%s Should not be called in AP mode\n", __func__); return; } @@ -2552,7 +2552,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) default: IWL_ERROR("%s Should not be called in %d mode\n", - __FUNCTION__, priv->iw_mode); + __func__, priv->iw_mode); break; } @@ -3794,7 +3794,7 @@ static ssize_t show_measurement(struct device *d, struct iwl_priv *priv = dev_get_drvdata(d); struct iwl4965_spectrum_notification measure_report; u32 size = sizeof(measure_report), len = 0, ofs = 0; - u8 *data = (u8 *) & measure_report; + u8 *data = (u8 *)&measure_report; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); @@ -3934,7 +3934,7 @@ static ssize_t show_power_level(struct device *d, p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO)?"fixed":"auto"); p += sprintf(p, "\tINDEX:%d", level); p += sprintf(p, "\n"); - return (p - buf + 1); + return p - buf + 1; } static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, @@ -4009,7 +4009,7 @@ static ssize_t show_statistics(struct device *d, struct iwl_priv *priv = dev_get_drvdata(d); u32 size = sizeof(struct iwl_notif_statistics); u32 len = 0, ofs = 0; - u8 *data = (u8 *) & priv->statistics; + u8 *data = (u8 *)&priv->statistics; int rc = 0; if (!iwl_is_alive(priv)) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 96beacf703a..9bd61809129 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -383,8 +383,8 @@ void iwl_reset_qos(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_reset_qos); -#define MAX_BIT_RATE_40_MHZ 0x96; /* 150 Mbps */ -#define MAX_BIT_RATE_20_MHZ 0x48; /* 72 Mbps */ +#define MAX_BIT_RATE_40_MHZ 0x96 /* 150 Mbps */ +#define MAX_BIT_RATE_20_MHZ 0x48 /* 72 Mbps */ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, struct ieee80211_ht_info *ht_info, enum ieee80211_band band) diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index d6d729e86bd..b4ffd33ef98 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -33,12 +33,12 @@ #define IWL_DEBUG(level, fmt, args...) \ do { if (priv->debug_level & (level)) \ dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) + in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) #define IWL_DEBUG_LIMIT(level, fmt, args...) \ do { if ((priv->debug_level & (level)) && net_ratelimit()) \ dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) + in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) #ifdef CONFIG_IWLWIFI_DEBUGFS struct iwl_debugfs { diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index ed948dc59b3..20db0eb636a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -231,7 +231,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, DECLARE_MAC_BUF(mac); buf = kmalloc(bufsz, GFP_KERNEL); - if(!buf) + if (!buf) return -ENOMEM; pos += scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n", @@ -364,16 +364,19 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) { struct iwl_debugfs *dbgfs; struct dentry *phyd = priv->hw->wiphy->debugfsdir; + int ret = 0; dbgfs = kzalloc(sizeof(struct iwl_debugfs), GFP_KERNEL); if (!dbgfs) { + ret = -ENOMEM; goto err; } priv->dbgfs = dbgfs; dbgfs->name = name; dbgfs->dir_drv = debugfs_create_dir(name, phyd); - if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)){ + if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)) { + ret = -ENOENT; goto err; } @@ -394,7 +397,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) err: IWL_ERROR("Can't open the debugfs directory\n"); iwl_dbgfs_unregister(priv); - return -ENOENT; + return ret; } EXPORT_SYMBOL(iwl_dbgfs_register); @@ -404,7 +407,7 @@ EXPORT_SYMBOL(iwl_dbgfs_register); */ void iwl_dbgfs_unregister(struct iwl_priv *priv) { - if (!(priv->dbgfs)) + if (!priv->dbgfs) return; DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_eeprom); diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 4a08a1b5097..bce53830b30 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -273,8 +273,7 @@ EXPORT_SYMBOL(iwl_eeprom_init); void iwl_eeprom_free(struct iwl_priv *priv) { - if(priv->eeprom) - kfree(priv->eeprom); + kfree(priv->eeprom); priv->eeprom = NULL; } EXPORT_SYMBOL(iwl_eeprom_free); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 10af82170f6..60a6e010603 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -823,7 +823,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, if (lq->sta_id == 0xFF) lq->sta_id = IWL_AP_ID; - iwl_dump_lq_cmd(priv,lq); + iwl_dump_lq_cmd(priv, lq); if (iwl_is_associated(priv) && priv->assoc_station_added) return iwl_send_cmd(priv, &cmd); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 7c82ecfa30a..eb41b02b506 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -275,10 +275,8 @@ static int iwl3945_tx_queue_alloc(struct iwl3945_priv *priv, return 0; error: - if (txq->txb) { - kfree(txq->txb); - txq->txb = NULL; - } + kfree(txq->txb); + txq->txb = NULL; return -ENOMEM; } @@ -365,10 +363,8 @@ void iwl3945_tx_queue_free(struct iwl3945_priv *priv, struct iwl3945_tx_queue *t txq->q.n_bd, txq->bd, txq->q.dma_addr); /* De-alloc array of per-TFD driver data */ - if (txq->txb) { - kfree(txq->txb); - txq->txb = NULL; - } + kfree(txq->txb); + txq->txb = NULL; /* 0-fill queue descriptor structure */ memset(txq, 0, sizeof(*txq)); @@ -2703,9 +2699,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; - if (qc) { + if (qc) priv->stations[sta_id].tid[tid].seq_number = seq_number; - } } else { wait_write_ptr = 1; txq->need_update = 0; @@ -3813,7 +3808,7 @@ int iwl3945_calc_db_from_ratio(int sig_ratio) /* 100:1 or higher, divide by 10 and use table, * add 20 dB to make up for divide by 10 */ if (sig_ratio >= 100) - return (20 + (int)ratio2dB[sig_ratio/10]); + return 20 + (int)ratio2dB[sig_ratio/10]; /* We shouldn't see this */ if (sig_ratio < 1) @@ -5088,7 +5083,7 @@ static void iwl3945_dealloc_ucode_pci(struct iwl3945_priv *priv) * iwl3945_verify_inst_full - verify runtime uCode image in card vs. host, * looking at all data. */ -static int iwl3945_verify_inst_full(struct iwl3945_priv *priv, __le32 * image, u32 len) +static int iwl3945_verify_inst_full(struct iwl3945_priv *priv, __le32 *image, u32 len) { u32 val; u32 save_len = len; @@ -5237,7 +5232,7 @@ static int iwl3945_verify_bsm(struct iwl3945_priv *priv) val = iwl3945_read_prph(priv, BSM_WR_DWCOUNT_REG); for (reg = BSM_SRAM_LOWER_BOUND; reg < BSM_SRAM_LOWER_BOUND + len; - reg += sizeof(u32), image ++) { + reg += sizeof(u32), image++) { val = iwl3945_read_prph(priv, reg); if (val != le32_to_cpu(*image)) { IWL_ERROR("BSM uCode verification failed at " @@ -6336,7 +6331,7 @@ static void iwl3945_bg_post_associate(struct work_struct *data) DECLARE_MAC_BUF(mac); if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { - IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__); + IWL_ERROR("%s Should not be called in AP mode\n", __func__); return; } @@ -6417,7 +6412,7 @@ static void iwl3945_bg_post_associate(struct work_struct *data) default: IWL_ERROR("%s Should not be called in %d mode\n", - __FUNCTION__, priv->iw_mode); + __func__, priv->iw_mode); break; } @@ -7456,7 +7451,7 @@ static ssize_t show_measurement(struct device *d, struct iwl3945_priv *priv = dev_get_drvdata(d); struct iwl3945_spectrum_notification measure_report; u32 size = sizeof(measure_report), len = 0, ofs = 0; - u8 *data = (u8 *) & measure_report; + u8 *data = (u8 *)&measure_report; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); @@ -7627,7 +7622,7 @@ static ssize_t show_power_level(struct device *d, else p += sprintf(p, " \n"); - return (p - buf + 1); + return p - buf + 1; } @@ -7649,7 +7644,7 @@ static ssize_t show_statistics(struct device *d, struct iwl3945_priv *priv = dev_get_drvdata(d); u32 size = sizeof(struct iwl3945_notif_statistics); u32 len = 0, ofs = 0; - u8 *data = (u8 *) & priv->statistics; + u8 *data = (u8 *)&priv->statistics; int rc = 0; if (!iwl3945_is_alive(priv)) @@ -8003,16 +7998,16 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e /* nic init */ iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - - iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - err = iwl3945_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (err < 0) { - IWL_DEBUG_INFO("Failed to init the card\n"); + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + + iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + err = iwl3945_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (err < 0) { + IWL_DEBUG_INFO("Failed to init the card\n"); goto out_remove_sysfs; - } + } /* Read the EEPROM */ err = iwl3945_eeprom_init(priv); if (err) { @@ -8114,9 +8109,8 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) iwl3945_unset_hw_setting(priv); iwl3945_clear_stations_table(priv); - if (priv->mac80211_registered) { + if (priv->mac80211_registered) ieee80211_unregister_hw(priv->hw); - } /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); -- cgit v1.2.3 From 4fc22b21b3fcb3580c32b70605ef114178f8e611 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 21 Jul 2008 18:54:42 +0300 Subject: iwlwifi: rename 4965 to AGN This patch renames driver name from 4965 to AGN The driver supports both 4965AGN and 5000AGN family The driver's original module name iwl4965.ko remains as an alias Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 98 ++++++++++++++++++---------------- drivers/net/wireless/iwlwifi/Makefile | 11 ++-- drivers/net/wireless/iwlwifi/iwl-agn.c | 15 +++--- drivers/net/wireless/iwlwifi/iwl-dev.h | 7 +-- 4 files changed, 68 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 82b66a3d3a5..b0ac0ce3fb9 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -14,18 +14,49 @@ config IWLWIFI_LEDS default n config IWLWIFI_RFKILL - boolean "IWLWIFI RF kill support" + boolean "Iwlwifi RF kill support" depends on IWLCORE -config IWL4965 - tristate "Intel Wireless WiFi 4965AGN" +config IWLWIFI_DEBUG + bool "Enable full debugging output in iwlagn driver" + depends on IWLCORE + ---help--- + This option will enable debug tracing output for the iwlwifi drivers + + This will result in the kernel module being ~100k larger. You can + control which debug output is sent to the kernel log by setting the + value in + + /sys/class/net/wlan0/device/debug_level + + This entry will only exist if this option is enabled. + + To set a value, simply echo an 8-byte hex value to the same file: + + % echo 0x43fff > /sys/class/net/wlan0/device/debug_level + + You can find the list of debug mask values in: + drivers/net/wireless/iwlwifi/iwl-debug.h + + If this is your first time using this driver, you should say Y here + as the debug information can assist others in helping you resolve + any problems you may encounter. + +config IWLWIFI_DEBUGFS + bool "Iwlwifi debugfs support" + depends on IWLCORE && IWLWIFI_DEBUG && MAC80211_DEBUGFS + ---help--- + Enable creation of debugfs files for the iwlwifi drivers. + +config IWLAGN + tristate "Intel Wireless WiFi Next Gen AGN" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL select FW_LOADER select IWLCORE ---help--- Select to build the driver supporting the: - Intel Wireless WiFi Link 4965AGN + Intel Wireless WiFi Link Next-Gen AGN This driver uses the kernel's mac80211 subsystem. @@ -42,60 +73,33 @@ config IWL4965 If you want to compile the driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read . The - module will be called iwl4965.ko. - -config IWL4965_LEDS - bool "Enable LEDS features in iwl4965 driver" - depends on IWL4965 - select IWLWIFI_LEDS - ---help--- - This option enables LEDS for the iwlwifi drivers + module will be called iwlagn.ko. - -config IWL4965_SPECTRUM_MEASUREMENT - bool "Enable Spectrum Measurement in iwl4965 driver" - depends on IWL4965 +config IWLAGN_SPECTRUM_MEASUREMENT + bool "Enable Spectrum Measurement in iwlagn driver" + depends on IWLAGN ---help--- - This option will enable spectrum measurement for the iwl4965 driver. + This option will enable spectrum measurement for the iwlagn driver. -config IWLWIFI_DEBUG - bool "Enable full debugging output in iwl4965 driver" - depends on IWL4965 +config IWLAGN_LEDS + bool "Enable LEDS features in iwlagn driver" + depends on IWLAGN + select IWLWIFI_LEDS ---help--- - This option will enable debug tracing output for the iwl4965 - driver. - - This will result in the kernel module being ~100k larger. You can - control which debug output is sent to the kernel log by setting the - value in - - /sys/class/net/wlan0/device/debug_level - - This entry will only exist if this option is enabled. - - To set a value, simply echo an 8-byte hex value to the same file: - - % echo 0x43fff > /sys/class/net/wlan0/device/debug_level + This option enables LEDS for the iwlagn drivers - You can find the list of debug mask values in: - drivers/net/wireless/iwlwifi/iwl-4965-debug.h - If this is your first time using this driver, you should say Y here - as the debug information can assist others in helping you resolve - any problems you may encounter. +config IWL4965 + bool "Intel Wireless WiFi 4965AGN" + depends on IWLAGN + ---help--- + This option enables support for Intel Wireless WiFi Link 4965AGN config IWL5000 bool "Intel Wireless WiFi 5000AGN" - depends on IWL4965 + depends on IWLAGN ---help--- This option enables support for Intel Wireless WiFi Link 5000AGN Family - Dependency on 4965 is temporary - -config IWLWIFI_DEBUGFS - bool "Iwlwifi debugfs support" - depends on IWLCORE && IWLWIFI_DEBUG && MAC80211_DEBUGFS - ---help--- - Enable creation of debugfs files for the iwlwifi drivers. config IWL3945 tristate "Intel PRO/Wireless 3945ABG/BG Network Connection" diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 6bf3998736b..47aa28f6a51 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -6,13 +6,14 @@ iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o +obj-$(CONFIG_IWLAGN) += iwlagn.o +iwlagn-objs := iwl-agn.o iwl-agn-rs.o + +iwlagn-$(CONFIG_IWL4965) += iwl-4965.o +iwlagn-$(CONFIG_IWL5000) += iwl-5000.o + obj-$(CONFIG_IWL3945) += iwl3945.o iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl3945-$(CONFIG_IWL3945_LEDS) += iwl-3945-led.o -obj-$(CONFIG_IWL4965) += iwl4965.o -iwl4965-objs := iwl-agn.o iwl-4965.o iwl-agn-rs.o - -iwl4965-$(CONFIG_IWL5000) += iwl-5000.o - diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 4ff0636dbdd..6503b3ac8d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -73,7 +73,7 @@ #define VD #endif -#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT +#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT #define VS "s" #else #define VS @@ -86,6 +86,7 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); +MODULE_ALIAS("iwl4965"); /*************** STATION TABLE MANAGEMENT **** * mac80211 should be examined to determine if sta_info is duplicating @@ -883,7 +884,7 @@ static void iwl4965_set_rate(struct iwl_priv *priv) (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; } -#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT +#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT #include "iwl-spectrum.h" @@ -1087,7 +1088,7 @@ static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { -#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT +#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif); @@ -3786,7 +3787,7 @@ static ssize_t store_filter_flags(struct device *d, static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, store_filter_flags); -#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT +#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT static ssize_t show_measurement(struct device *d, struct device_attribute *attr, char *buf) @@ -3857,7 +3858,7 @@ static ssize_t store_measurement(struct device *d, static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, show_measurement, store_measurement); -#endif /* CONFIG_IWL4965_SPECTRUM_MEASUREMENT */ +#endif /* CONFIG_IWLAGN_SPECTRUM_MEASUREMENT */ static ssize_t store_retry_rate(struct device *d, struct device_attribute *attr, @@ -4105,7 +4106,7 @@ static struct attribute *iwl4965_sysfs_entries[] = { &dev_attr_channels.attr, &dev_attr_flags.attr, &dev_attr_filter_flags.attr, -#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT +#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT &dev_attr_measurement.attr, #endif &dev_attr_power_level.attr, @@ -4457,8 +4458,10 @@ static int iwl4965_pci_resume(struct pci_dev *pdev) /* Hardware specific file defines the PCI IDs table for that hardware module */ static struct pci_device_id iwl_hw_card_ids[] = { +#ifdef CONFIG_IWL4965 {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)}, {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)}, +#endif /* CONFIG_IWL4965 */ #ifdef CONFIG_IWL5000 {IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bg_cfg)}, {IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bg_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 7ac56b1350b..848786ab791 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -36,7 +36,7 @@ #include #include -#define DRV_NAME "iwl4965" +#define DRV_NAME "iwlagn" #include "iwl-rfkill.h" #include "iwl-eeprom.h" #include "iwl-4965-hw.h" @@ -808,14 +808,11 @@ struct iwl_chain_noise_data { #define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ -#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT - enum { MEASUREMENT_READY = (1 << 0), MEASUREMENT_ACTIVE = (1 << 1), }; -#endif #define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ @@ -840,7 +837,7 @@ struct iwl_priv { struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; -#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT +#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT /* spectrum measurement report caching */ struct iwl4965_spectrum_notification measure_report; u8 measurement_status; -- cgit v1.2.3 From 5cbbb376d65ed181ed290cea505ba37a0425ee25 Mon Sep 17 00:00:00 2001 From: Sven Wegener Date: Fri, 1 Aug 2008 21:57:16 +0200 Subject: iwlwifi: Don't use buffer allocated on the stack for led names Having the buffer on the stack and even re-using it for all led devices is bad. Not being able to resolve the name member of the led device structure to a meaningful value leads to confusion during ad-hoc debugging and potential breakage in the future, if we ever decide to access the name member outside of the registration function. Move the buffer to our private per led device structures so that it is accessible after registration. A quick grep didn't yield any occurence of using the led device name parameter outside of the led device registration function, so currently we should already be safe for normal operation. Signed-off-by: Sven Wegener Cc: Richard Purdie Acked-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-led.c | 33 +++++++++++++++-------------- drivers/net/wireless/iwlwifi/iwl-3945-led.h | 1 + drivers/net/wireless/iwlwifi/iwl-led.c | 29 ++++++++++++++----------- drivers/net/wireless/iwlwifi/iwl-led.h | 1 + 4 files changed, 36 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index 6be1fe13fa5..d3336966b6b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -206,12 +206,12 @@ static void iwl3945_led_brightness_set(struct led_classdev *led_cdev, static int iwl3945_led_register_led(struct iwl3945_priv *priv, struct iwl3945_led *led, enum led_type type, u8 set_led, - const char *name, char *trigger) + char *trigger) { struct device *device = wiphy_dev(priv->hw->wiphy); int ret; - led->led_dev.name = name; + led->led_dev.name = led->name; led->led_dev.brightness_set = iwl3945_led_brightness_set; led->led_dev.default_trigger = trigger; @@ -308,7 +308,6 @@ void iwl3945_led_background(struct iwl3945_priv *priv) int iwl3945_led_register(struct iwl3945_priv *priv) { char *trigger; - char name[32]; int ret; priv->last_blink_rate = 0; @@ -318,7 +317,8 @@ int iwl3945_led_register(struct iwl3945_priv *priv) priv->allow_blinking = 0; trigger = ieee80211_get_radio_led_name(priv->hw); - snprintf(name, sizeof(name), "iwl-%s:radio", + snprintf(priv->led[IWL_LED_TRG_RADIO].name, + sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s:radio", wiphy_name(priv->hw->wiphy)); priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on; @@ -327,19 +327,20 @@ int iwl3945_led_register(struct iwl3945_priv *priv) ret = iwl3945_led_register_led(priv, &priv->led[IWL_LED_TRG_RADIO], - IWL_LED_TRG_RADIO, 1, - name, trigger); + IWL_LED_TRG_RADIO, 1, trigger); + if (ret) goto exit_fail; trigger = ieee80211_get_assoc_led_name(priv->hw); - snprintf(name, sizeof(name), "iwl-%s:assoc", + snprintf(priv->led[IWL_LED_TRG_ASSOC].name, + sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s:assoc", wiphy_name(priv->hw->wiphy)); ret = iwl3945_led_register_led(priv, &priv->led[IWL_LED_TRG_ASSOC], - IWL_LED_TRG_ASSOC, 0, - name, trigger); + IWL_LED_TRG_ASSOC, 0, trigger); + /* for assoc always turn led on */ priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on; priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on; @@ -349,14 +350,13 @@ int iwl3945_led_register(struct iwl3945_priv *priv) goto exit_fail; trigger = ieee80211_get_rx_led_name(priv->hw); - snprintf(name, sizeof(name), "iwl-%s:RX", + snprintf(priv->led[IWL_LED_TRG_RX].name, + sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s:RX", wiphy_name(priv->hw->wiphy)); - ret = iwl3945_led_register_led(priv, &priv->led[IWL_LED_TRG_RX], - IWL_LED_TRG_RX, 0, - name, trigger); + IWL_LED_TRG_RX, 0, trigger); priv->led[IWL_LED_TRG_RX].led_on = iwl3945_led_associated; priv->led[IWL_LED_TRG_RX].led_off = iwl3945_led_associated; @@ -366,13 +366,14 @@ int iwl3945_led_register(struct iwl3945_priv *priv) goto exit_fail; trigger = ieee80211_get_tx_led_name(priv->hw); - snprintf(name, sizeof(name), "iwl-%s:TX", + snprintf(priv->led[IWL_LED_TRG_TX].name, + sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s:TX", wiphy_name(priv->hw->wiphy)); ret = iwl3945_led_register_led(priv, &priv->led[IWL_LED_TRG_TX], - IWL_LED_TRG_TX, 0, - name, trigger); + IWL_LED_TRG_TX, 0, trigger); + priv->led[IWL_LED_TRG_TX].led_on = iwl3945_led_associated; priv->led[IWL_LED_TRG_TX].led_off = iwl3945_led_associated; priv->led[IWL_LED_TRG_TX].led_pattern = iwl3945_led_pattern; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h index 47b7e0bac80..2fbd126c134 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h @@ -50,6 +50,7 @@ enum led_type { struct iwl3945_led { struct iwl3945_priv *priv; struct led_classdev led_dev; + char name[32]; int (*led_on) (struct iwl3945_priv *priv, int led_id); int (*led_off) (struct iwl3945_priv *priv, int led_id); diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 0a01f091c51..cb11c4a4d69 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -242,12 +242,12 @@ static void iwl_led_brightness_set(struct led_classdev *led_cdev, */ static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led, enum led_type type, u8 set_led, - const char *name, char *trigger) + char *trigger) { struct device *device = wiphy_dev(priv->hw->wiphy); int ret; - led->led_dev.name = name; + led->led_dev.name = led->name; led->led_dev.brightness_set = iwl_led_brightness_set; led->led_dev.default_trigger = trigger; @@ -345,7 +345,6 @@ EXPORT_SYMBOL(iwl_leds_background); int iwl_leds_register(struct iwl_priv *priv) { char *trigger; - char name[32]; int ret; priv->last_blink_rate = 0; @@ -354,7 +353,8 @@ int iwl_leds_register(struct iwl_priv *priv) priv->allow_blinking = 0; trigger = ieee80211_get_radio_led_name(priv->hw); - snprintf(name, sizeof(name), "iwl-%s:radio", + snprintf(priv->led[IWL_LED_TRG_RADIO].name, + sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s:radio", wiphy_name(priv->hw->wiphy)); priv->led[IWL_LED_TRG_RADIO].led_on = iwl4965_led_on_reg; @@ -362,16 +362,17 @@ int iwl_leds_register(struct iwl_priv *priv) priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL; ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO], - IWL_LED_TRG_RADIO, 1, name, trigger); + IWL_LED_TRG_RADIO, 1, trigger); if (ret) goto exit_fail; trigger = ieee80211_get_assoc_led_name(priv->hw); - snprintf(name, sizeof(name), "iwl-%s:assoc", + snprintf(priv->led[IWL_LED_TRG_ASSOC].name, + sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s:assoc", wiphy_name(priv->hw->wiphy)); ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_ASSOC], - IWL_LED_TRG_ASSOC, 0, name, trigger); + IWL_LED_TRG_ASSOC, 0, trigger); /* for assoc always turn led on */ priv->led[IWL_LED_TRG_ASSOC].led_on = iwl_led_associate; @@ -382,11 +383,12 @@ int iwl_leds_register(struct iwl_priv *priv) goto exit_fail; trigger = ieee80211_get_rx_led_name(priv->hw); - snprintf(name, sizeof(name), "iwl-%s:RX", wiphy_name(priv->hw->wiphy)); - + snprintf(priv->led[IWL_LED_TRG_RX].name, + sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s:RX", + wiphy_name(priv->hw->wiphy)); ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RX], - IWL_LED_TRG_RX, 0, name, trigger); + IWL_LED_TRG_RX, 0, trigger); priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated; priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated; @@ -396,9 +398,12 @@ int iwl_leds_register(struct iwl_priv *priv) goto exit_fail; trigger = ieee80211_get_tx_led_name(priv->hw); - snprintf(name, sizeof(name), "iwl-%s:TX", wiphy_name(priv->hw->wiphy)); + snprintf(priv->led[IWL_LED_TRG_TX].name, + sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s:TX", + wiphy_name(priv->hw->wiphy)); + ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_TX], - IWL_LED_TRG_TX, 0, name, trigger); + IWL_LED_TRG_TX, 0, trigger); priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated; priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated; diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index 1980ae5a7e8..588c9ad20e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -52,6 +52,7 @@ enum led_type { struct iwl_led { struct iwl_priv *priv; struct led_classdev led_dev; + char name[32]; int (*led_on) (struct iwl_priv *priv, int led_id); int (*led_off) (struct iwl_priv *priv, int led_id); -- cgit v1.2.3 From d06193f311102b2c990ec5f66b470ea49ecc73a4 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 3 Aug 2008 23:36:01 +0200 Subject: rt2x00: Disable link tuning in rt2500usb In the legacy rt2570 driver the link tuner was never really called. And now the reason has finally become apparent: It breaks TX capabilities As soon as the device has been associated all following TX frames will be queued in the hardware and never transmitted to the air. Disabling sections of the link tuner did not have the expected result, but completely disabling the link tuner did have the right result (Both of my rt2570 devices came back to life). This should fix Fedora bug: 411481 v2: Fix typos Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index c6f6eb6e17a..cd5af656932 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -633,6 +633,16 @@ static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev) rt2x00dev->link.vgc_level = value; } +/* + * NOTE: This function is directly ported from legacy driver, but + * despite it being declared it was never called. Although link tuning + * sounds like a good idea, and usually works well for the other drivers, + * it does _not_ work with rt2500usb. Enabling this function will result + * in TX capabilities only until association kicks in. Immediately + * after the successful association all TX frames will be kept in the + * hardware queue and never transmitted. + */ +#if 0 static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev) { int rssi = rt2x00_get_link_rssi(&rt2x00dev->link); @@ -752,6 +762,9 @@ dynamic_cca_tune: rt2x00dev->link.vgc_level = r17; } } +#else +#define rt2500usb_link_tuner NULL +#endif /* * Initialization functions. @@ -1737,6 +1750,7 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); + __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags); /* * Set the rssi offset. -- cgit v1.2.3 From 6041e2a08c50e3fcaf1e56422bfafda62c597cea Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 3 Aug 2008 17:58:36 -0500 Subject: p54: Fix potential concurrent access to private data Experience with the rtl8187 driver has shown that mac80211 can make calls to the config callback routine in rapid succession. This patch creates a mutex that protects the private data in several of the routines called by mac80211. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54.h | 1 + drivers/net/wireless/p54/p54common.c | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index c6f27b9022f..cac9a515b82 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -52,6 +52,7 @@ struct p54_common { int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); int mode; + struct mutex conf_mutex; u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; struct pda_iq_autocal_entry *iq_autocal; diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index ffaf7a6b681..4da89ea9b56 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -886,9 +886,12 @@ static void p54_remove_interface(struct ieee80211_hw *dev, static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) { int ret; + struct p54_common *priv = dev->priv; + mutex_lock(&priv->conf_mutex); ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq)); p54_set_vdcf(dev); + mutex_unlock(&priv->conf_mutex); return ret; } @@ -898,10 +901,12 @@ static int p54_config_interface(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; + mutex_lock(&priv->conf_mutex); p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 0, 1, 0, 0xF642); p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 2, 0, 0, 0); p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0); memcpy(priv->bssid, conf->bssid, ETH_ALEN); + mutex_unlock(&priv->conf_mutex); return 0; } @@ -1009,6 +1014,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) } p54_init_vdcf(dev); + mutex_init(&priv->conf_mutex); return dev; } -- cgit v1.2.3 From 4c43e0d0ecd5196ed5c67f64ed2f1860770eed34 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 4 Aug 2008 16:00:39 +0800 Subject: iwlwifi: HW bug fixes This patch adds few HW bug fixes. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 15 +++++++++++++++ drivers/net/wireless/iwlwifi/iwl-csr.h | 10 +++++++++- drivers/net/wireless/iwlwifi/iwl-prph.h | 12 +++++++----- 3 files changed, 31 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index f7bbd12193f..1d793c093f1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -93,6 +93,13 @@ static int iwl5000_apm_init(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); + /* Set FH wait treshold to maximum (HW error during stress W/A) */ + iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); + + /* enable HAP INTA to move device L1a -> L0s */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); + iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL); /* set "initialization complete" bit to move adapter @@ -230,6 +237,14 @@ static void iwl5000_nic_config(struct iwl_priv *priv) CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); + /* W/A : NIC is stuck in a reset state after Early PCIe power off + * (PCIe power is lost before PERST# is asserted), + * causing ME FW to lose ownership and not being able to obtain it back. + */ + iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, + ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); + spin_unlock_irqrestore(&priv->lock, flags); } diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 545ed692d88..52629fbd835 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -104,6 +104,7 @@ * 3-2: 0 = A, 1 = B, 2 = C, 3 = D step */ #define CSR_HW_REV_WA_REG (CSR_BASE+0x22C) +#define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240) /* Bits for CSR_HW_IF_CONFIG_REG */ #define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010) @@ -118,7 +119,12 @@ #define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000) #define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000) -#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) +#define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) +#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) +#define CSR_HW_IF_CONFIG_REG_BIT_PCI_OWN_SEM (0x00400000) +#define CSR_HW_IF_CONFIG_REG_BIT_ME_OWN (0x02000000) +#define CSR_HW_IF_CONFIG_REG_BIT_WAKE_ME (0x08000000) + /* interrupt flags in INTA, set by uCode or hardware (e.g. dma), * acknowledged (reset) by host writing "1" to flagged bits. */ @@ -236,6 +242,8 @@ #define CSR39_ANA_PLL_CFG_VAL (0x01000000) #define CSR50_ANA_PLL_CFG_VAL (0x00880300) +/* HPET MEM debug */ +#define CSR_DBG_HPET_MEM_REG_VAL (0xFFFF0000) /*=== HBUS (Host-side Bus) ===*/ #define HBUS_BASE (0x400) /* diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 70d9c7568b9..ee5afd48d3a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -84,14 +84,16 @@ #define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200) #define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800) -#define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000) -#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) +#define APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS (0x00400000) +#define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000) +#define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000) +#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000) +#define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */ +#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000) -#define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000) -#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000) -#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x01000000) +#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) /** * BSM (Bootstrap State Machine) -- cgit v1.2.3 From da99c4b6c25964b90c79f19beccda208df1a865a Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Mon, 4 Aug 2008 16:00:40 +0800 Subject: iwlwifi: memory allocation optimization This patch optimizes memory allocation. The cmd member of iwl_tx_queue was allocated previously as a continuous block of memory. This patch allocates separate memory chunks for each command and maps/unmaps these chunks in the run time. Signed-off-by: Gregory Greenman Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 6 +-- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 +- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 2 +- drivers/net/wireless/iwlwifi/iwl-tx.c | 76 +++++++++++++++++++++++---------- 4 files changed, 59 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 1d793c093f1..56dbc8144a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -939,8 +939,8 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; if (txq_id != IWL_CMD_QUEUE_NUM) { - sta = txq->cmd[txq->q.write_ptr].cmd.tx.sta_id; - sec_ctl = txq->cmd[txq->q.write_ptr].cmd.tx.sec_ctl; + sta = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id; + sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl; switch (sec_ctl & TX_CMD_SEC_MSK) { case TX_CMD_SEC_CCM: @@ -979,7 +979,7 @@ static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, u8 sta = 0; if (txq_id != IWL_CMD_QUEUE_NUM) - sta = txq->cmd[txq->q.read_ptr].cmd.tx.sta_id; + sta = txq->cmd[txq->q.read_ptr]->cmd.tx.sta_id; shared_data->queues_byte_cnt_tbls[txq_id].tfd_offset[txq->q.read_ptr]. val = cpu_to_le16(1 | (sta << 12)); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 848786ab791..c19db438306 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -135,8 +135,7 @@ struct iwl_tx_info { struct iwl_tx_queue { struct iwl_queue q; struct iwl_tfd_frame *bd; - struct iwl_cmd *cmd; - dma_addr_t dma_addr_cmd; + struct iwl_cmd *cmd[TFD_TX_CMD_SLOTS]; struct iwl_tx_info *txb; int need_update; int sched_retry; diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 8fa991b7202..6512834bb91 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -228,7 +228,7 @@ cancel: * TX cmd queue. Otherwise in case the cmd comes * in later, it will possibly set an invalid * address (cmd->meta.source). */ - qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx]; + qcmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx]; qcmd->meta.flags &= ~CMD_WANT_SKB; } fail: diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 39f19ebee97..aa98c76d819 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -208,11 +208,12 @@ EXPORT_SYMBOL(iwl_txq_update_write_ptr); * Free all buffers. * 0-fill, but do not free "txq" descriptor structure. */ -static void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) +static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) { + struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct iwl_queue *q = &txq->q; struct pci_dev *dev = priv->pci_dev; - int len; + int i, slots_num, len; if (q->n_bd == 0) return; @@ -227,7 +228,12 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) len += IWL_MAX_SCAN_SIZE; /* De-alloc array of command/tx buffers */ - pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); + slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? + TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; + for (i = 0; i < slots_num; i++) + kfree(txq->cmd[i]); + if (txq_id == IWL_CMD_QUEUE_NUM) + kfree(txq->cmd[slots_num]); /* De-alloc circular buffer of TFDs */ if (txq->q.n_bd) @@ -400,8 +406,7 @@ static int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, int slots_num, u32 txq_id) { - struct pci_dev *dev = priv->pci_dev; - int len; + int i, len; int rc = 0; /* @@ -412,17 +417,25 @@ static int iwl_tx_queue_init(struct iwl_priv *priv, * For normal Tx queues (all other queues), no super-size command * space is needed. */ - len = sizeof(struct iwl_cmd) * slots_num; - if (txq_id == IWL_CMD_QUEUE_NUM) - len += IWL_MAX_SCAN_SIZE; - txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd); - if (!txq->cmd) - return -ENOMEM; + len = sizeof(struct iwl_cmd); + for (i = 0; i <= slots_num; i++) { + if (i == slots_num) { + if (txq_id == IWL_CMD_QUEUE_NUM) + len += IWL_MAX_SCAN_SIZE; + else + continue; + } + + txq->cmd[i] = kmalloc(len, GFP_KERNEL | GFP_DMA); + if (!txq->cmd[i]) + return -ENOMEM; + } /* Alloc driver data array and TFD circular buffer */ rc = iwl_tx_queue_alloc(priv, txq, txq_id); if (rc) { - pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); + for (i = 0; i < slots_num; i++) + kfree(txq->cmd[i]); return -ENOMEM; } @@ -451,7 +464,7 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv) /* Tx queues */ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) - iwl_tx_queue_free(priv, &priv->txq[txq_id]); + iwl_tx_queue_free(priv, txq_id); /* Keep-warm buffer */ iwl_kw_free(priv); @@ -859,7 +872,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) txq->txb[q->write_ptr].skb[0] = skb; /* Set up first empty entry in queue's array of Tx/cmd buffers */ - out_cmd = &txq->cmd[idx]; + out_cmd = txq->cmd[idx]; tx_cmd = &out_cmd->cmd.tx; memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd)); @@ -899,8 +912,9 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Physical address of this Tx command's header (not MAC header!), * within command buffer array. */ - txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx + - offsetof(struct iwl_cmd, hdr); + txcmd_phys = pci_map_single(priv->pci_dev, out_cmd, + sizeof(struct iwl_cmd), PCI_DMA_TODEVICE); + txcmd_phys += offsetof(struct iwl_cmd, hdr); /* Add buffer containing Tx command and MAC(!) header to TFD's * first entry */ @@ -1004,7 +1018,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) u32 idx; u16 fix_size; dma_addr_t phys_addr; - int ret; + int len, ret; unsigned long flags; cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len); @@ -1034,7 +1048,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) control_flags = (u32 *) tfd; idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE); - out_cmd = &txq->cmd[idx]; + out_cmd = txq->cmd[idx]; out_cmd->hdr.cmd = cmd->id; memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta)); @@ -1048,9 +1062,11 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) INDEX_TO_SEQ(q->write_ptr)); if (out_cmd->meta.flags & CMD_SIZE_HUGE) out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); - - phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx + - offsetof(struct iwl_cmd, hdr); + len = (idx == TFD_CMD_SLOTS) ? + IWL_MAX_SCAN_SIZE : sizeof(struct iwl_cmd); + phys_addr = pci_map_single(priv->pci_dev, out_cmd, len, + PCI_DMA_TODEVICE); + phys_addr += offsetof(struct iwl_cmd, hdr); iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " @@ -1115,6 +1131,9 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) { struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct iwl_queue *q = &txq->q; + struct iwl_tfd_frame *bd = &txq->bd[index]; + dma_addr_t dma_addr; + int is_odd, buf_len; int nfreed = 0; if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) { @@ -1132,6 +1151,19 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) q->write_ptr, q->read_ptr); queue_work(priv->workqueue, &priv->restart); } + is_odd = (index/2) & 0x1; + if (is_odd) { + dma_addr = IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) | + (IWL_GET_BITS(bd->pa[index], + tb2_addr_hi20) << 16); + buf_len = IWL_GET_BITS(bd->pa[index], tb2_len); + } else { + dma_addr = le32_to_cpu(bd->pa[index].tb1_addr); + buf_len = IWL_GET_BITS(bd->pa[index], tb1_len); + } + + pci_unmap_single(priv->pci_dev, dma_addr, buf_len, + PCI_DMA_TODEVICE); nfreed++; } } @@ -1163,7 +1195,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); - cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; + cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; /* Input error checking is done when commands are added to queue. */ if (cmd->meta.flags & CMD_WANT_SKB) { -- cgit v1.2.3 From caab8f1a5d0da583b6ffe41afea2774c676444ca Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 4 Aug 2008 16:00:42 +0800 Subject: iwlwifi: implement iwl5000_calc_rssi This patch implements rssi calculation for 5000 HW. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 35 +++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-5000.c | 39 +++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-commands.h | 35 +++++++++++++---- drivers/net/wireless/iwlwifi/iwl-core.h | 2 + drivers/net/wireless/iwlwifi/iwl-rx.c | 59 ++++++++--------------------- 5 files changed, 119 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 718f9d9e494..22bb26985c2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2258,6 +2258,40 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); } +static int iwl4965_calc_rssi(struct iwl_priv *priv, + struct iwl_rx_phy_res *rx_resp) +{ + /* data from PHY/DSP regarding signal strength, etc., + * contents are always there, not configurable by host. */ + struct iwl4965_rx_non_cfg_phy *ncphy = + (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy_buf; + u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL49_AGC_DB_MASK) + >> IWL49_AGC_DB_POS; + + u32 valid_antennae = + (le16_to_cpu(rx_resp->phy_flags) & IWL49_RX_PHY_FLAGS_ANTENNAE_MASK) + >> IWL49_RX_PHY_FLAGS_ANTENNAE_OFFSET; + u8 max_rssi = 0; + u32 i; + + /* Find max rssi among 3 possible receivers. + * These values are measured by the digital signal processor (DSP). + * They should stay fairly constant even as the signal strength varies, + * if the radio's automatic gain control (AGC) is working right. + * AGC value (see below) will provide the "interesting" info. */ + for (i = 0; i < 3; i++) + if (valid_antennae & (1 << i)) + max_rssi = max(ncphy->rssi_info[i << 1], max_rssi); + + IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n", + ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4], + max_rssi, agc); + + /* dBm = max_rssi dB - agc dB - constant. + * Higher AGC (higher radio gain) means lower signal. */ + return max_rssi - agc - IWL_RSSI_OFFSET; +} + /* Set up 4965-specific Rx frame reply handlers */ static void iwl4965_rx_handler_setup(struct iwl_priv *priv) @@ -2289,6 +2323,7 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { .chain_noise_reset = iwl4965_chain_noise_reset, .gain_computation = iwl4965_gain_computation, .rts_tx_cmd_flag = iwl4965_rts_tx_cmd_flag, + .calc_rssi = iwl4965_calc_rssi, }; static struct iwl_lib_ops iwl4965_lib = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 56dbc8144a3..c5b104fd149 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1459,6 +1459,44 @@ static void iwl5000_temperature(struct iwl_priv *priv) priv->temperature = le32_to_cpu(priv->statistics.general.temperature); } +/* Calc max signal level (dBm) among 3 possible receivers */ +static int iwl5000_calc_rssi(struct iwl_priv *priv, + struct iwl_rx_phy_res *rx_resp) +{ + /* data from PHY/DSP regarding signal strength, etc., + * contents are always there, not configurable by host + */ + struct iwl5000_non_cfg_phy *ncphy = + (struct iwl5000_non_cfg_phy *)rx_resp->non_cfg_phy_buf; + u32 val, rssi_a, rssi_b, rssi_c, max_rssi; + u8 agc; + + val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_AGC_IDX]); + agc = (val & IWL50_OFDM_AGC_MSK) >> IWL50_OFDM_AGC_BIT_POS; + + /* Find max rssi among 3 possible receivers. + * These values are measured by the digital signal processor (DSP). + * They should stay fairly constant even as the signal strength varies, + * if the radio's automatic gain control (AGC) is working right. + * AGC value (see below) will provide the "interesting" info. + */ + val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_AB_IDX]); + rssi_a = (val & IWL50_OFDM_RSSI_A_MSK) >> IWL50_OFDM_RSSI_A_BIT_POS; + rssi_b = (val & IWL50_OFDM_RSSI_B_MSK) >> IWL50_OFDM_RSSI_B_BIT_POS; + val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_C_IDX]); + rssi_c = (val & IWL50_OFDM_RSSI_C_MSK) >> IWL50_OFDM_RSSI_C_BIT_POS; + + max_rssi = max_t(u32, rssi_a, rssi_b); + max_rssi = max_t(u32, max_rssi, rssi_c); + + IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n", + rssi_a, rssi_b, rssi_c, max_rssi, agc); + + /* dBm = max_rssi dB - agc dB - constant. + * Higher AGC (higher radio gain) means lower signal. */ + return max_rssi - agc - IWL_RSSI_OFFSET; +} + static struct iwl_hcmd_ops iwl5000_hcmd = { .rxon_assoc = iwl5000_send_rxon_assoc, }; @@ -1469,6 +1507,7 @@ static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { .gain_computation = iwl5000_gain_computation, .chain_noise_reset = iwl5000_chain_noise_reset, .rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag, + .calc_rssi = iwl5000_calc_rssi, }; static struct iwl_lib_ops iwl5000_lib = { diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 5e57f3ae2ea..28b5b09996e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1075,10 +1075,12 @@ struct iwl4965_rx_frame { } __attribute__ ((packed)); /* Fixed (non-configurable) rx data from phy */ -#define RX_PHY_FLAGS_ANTENNAE_OFFSET (4) -#define RX_PHY_FLAGS_ANTENNAE_MASK (0x70) -#define IWL_AGC_DB_MASK (0x3f80) /* MASK(7,13) */ -#define IWL_AGC_DB_POS (7) + +#define IWL49_RX_RES_PHY_CNT 14 +#define IWL49_RX_PHY_FLAGS_ANTENNAE_OFFSET (4) +#define IWL49_RX_PHY_FLAGS_ANTENNAE_MASK (0x70) +#define IWL49_AGC_DB_MASK (0x3f80) /* MASK(7,13) */ +#define IWL49_AGC_DB_POS (7) struct iwl4965_rx_non_cfg_phy { __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */ __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */ @@ -1086,12 +1088,30 @@ struct iwl4965_rx_non_cfg_phy { u8 pad[0]; } __attribute__ ((packed)); + +#define IWL50_RX_RES_PHY_CNT 8 +#define IWL50_RX_RES_AGC_IDX 1 +#define IWL50_RX_RES_RSSI_AB_IDX 2 +#define IWL50_RX_RES_RSSI_C_IDX 3 +#define IWL50_OFDM_AGC_MSK 0xfe00 +#define IWL50_OFDM_AGC_BIT_POS 9 +#define IWL50_OFDM_RSSI_A_MSK 0x00ff +#define IWL50_OFDM_RSSI_A_BIT_POS 0 +#define IWL50_OFDM_RSSI_B_MSK 0xff0000 +#define IWL50_OFDM_RSSI_B_BIT_POS 16 +#define IWL50_OFDM_RSSI_C_MSK 0x00ff +#define IWL50_OFDM_RSSI_C_BIT_POS 0 + +struct iwl5000_non_cfg_phy { + __le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT]; /* upto 8 phy entries */ +} __attribute__ ((packed)); + + /* * REPLY_RX = 0xc3 (response only, not a command) * Used only for legacy (non 11n) frames. */ -#define RX_RES_PHY_CNT 14 -struct iwl4965_rx_phy_res { +struct iwl_rx_phy_res { u8 non_cfg_phy_cnt; /* non configurable DSP phy data byte count */ u8 cfg_phy_cnt; /* configurable DSP phy data byte count */ u8 stat_id; /* configurable DSP phy data set ID */ @@ -1100,8 +1120,7 @@ struct iwl4965_rx_phy_res { __le32 beacon_time_stamp; /* beacon at on-air rise */ __le16 phy_flags; /* general phy flags: band, modulation, ... */ __le16 channel; /* channel number */ - __le16 non_cfg_phy[RX_RES_PHY_CNT]; /* upto 14 phy entries */ - __le32 reserved2; + u8 non_cfg_phy_buf[32]; /* for various implementations of non_cfg_phy */ __le32 rate_n_flags; /* RATE_MCS_* */ __le16 byte_count; /* frame's byte-count */ __le16 reserved3; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index eaefa42f37c..64f139e9744 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -95,6 +95,8 @@ struct iwl_hcmd_utils_ops { void (*chain_noise_reset)(struct iwl_priv *priv); void (*rts_tx_cmd_flag)(struct ieee80211_tx_info *info, __le32 *tx_flags); + int (*calc_rssi)(struct iwl_priv *priv, + struct iwl_rx_phy_res *rx_resp); }; struct iwl_lib_ops { diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index e2d9afba38a..f3f6ea49fdd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -791,7 +791,7 @@ static inline void iwl_dbg_report_frame(struct iwl_priv *priv, static void iwl_add_radiotap(struct iwl_priv *priv, struct sk_buff *skb, - struct iwl4965_rx_phy_res *rx_start, + struct iwl_rx_phy_res *rx_start, struct ieee80211_rx_status *stats, u32 ampdu_status) { @@ -1010,8 +1010,8 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, struct ieee80211_rx_status *stats) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_rx_phy_res *rx_start = (include_phy) ? - (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL; + struct iwl_rx_phy_res *rx_start = (include_phy) ? + (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : NULL; struct ieee80211_hdr *hdr; u16 len; __le32 *rx_end; @@ -1020,7 +1020,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, u32 ampdu_status_legacy; if (!include_phy && priv->last_phy_res[0]) - rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; + rx_start = (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; if (!rx_start) { IWL_ERROR("MPDU frame without a PHY data\n"); @@ -1032,8 +1032,8 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, len = le16_to_cpu(rx_start->byte_count); - rx_end = (__le32 *) ((u8 *) &pkt->u.raw[0] + - sizeof(struct iwl4965_rx_phy_res) + + rx_end = (__le32 *)((u8 *) &pkt->u.raw[0] + + sizeof(struct iwl_rx_phy_res) + rx_start->cfg_phy_cnt + len); } else { @@ -1084,40 +1084,13 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, } /* Calc max signal level (dBm) among 3 possible receivers */ -static int iwl_calc_rssi(struct iwl_priv *priv, - struct iwl4965_rx_phy_res *rx_resp) +static inline int iwl_calc_rssi(struct iwl_priv *priv, + struct iwl_rx_phy_res *rx_resp) { - /* data from PHY/DSP regarding signal strength, etc., - * contents are always there, not configurable by host. */ - struct iwl4965_rx_non_cfg_phy *ncphy = - (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy; - u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL_AGC_DB_MASK) - >> IWL_AGC_DB_POS; - - u32 valid_antennae = - (le16_to_cpu(rx_resp->phy_flags) & RX_PHY_FLAGS_ANTENNAE_MASK) - >> RX_PHY_FLAGS_ANTENNAE_OFFSET; - u8 max_rssi = 0; - u32 i; - - /* Find max rssi among 3 possible receivers. - * These values are measured by the digital signal processor (DSP). - * They should stay fairly constant even as the signal strength varies, - * if the radio's automatic gain control (AGC) is working right. - * AGC value (see below) will provide the "interesting" info. */ - for (i = 0; i < 3; i++) - if (valid_antennae & (1 << i)) - max_rssi = max(ncphy->rssi_info[i << 1], max_rssi); - - IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n", - ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4], - max_rssi, agc); - - /* dBm = max_rssi dB - agc dB - constant. - * Higher AGC (higher radio gain) means lower signal. */ - return max_rssi - agc - IWL_RSSI_OFFSET; + return priv->cfg->ops->utils->calc_rssi(priv, rx_resp); } + static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) { unsigned long flags; @@ -1180,9 +1153,9 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, * this rx packet for legacy frames, * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ int include_phy = (pkt->hdr.cmd == REPLY_RX); - struct iwl4965_rx_phy_res *rx_start = (include_phy) ? - (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : - (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; + struct iwl_rx_phy_res *rx_start = (include_phy) ? + (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : + (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; __le32 *rx_end; unsigned int len = 0; u16 fc; @@ -1210,7 +1183,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, if (!include_phy) { if (priv->last_phy_res[0]) - rx_start = (struct iwl4965_rx_phy_res *) + rx_start = (struct iwl_rx_phy_res *) &priv->last_phy_res[1]; else rx_start = NULL; @@ -1227,7 +1200,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, len = le16_to_cpu(rx_start->byte_count); rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + - sizeof(struct iwl4965_rx_phy_res) + len); + sizeof(struct iwl_rx_phy_res) + len); } else { struct iwl4965_rx_mpdu_res_start *amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; @@ -1316,6 +1289,6 @@ void iwl_rx_reply_rx_phy(struct iwl_priv *priv, struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; priv->last_phy_res[0] = 1; memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), - sizeof(struct iwl4965_rx_phy_res)); + sizeof(struct iwl_rx_phy_res)); } EXPORT_SYMBOL(iwl_rx_reply_rx_phy); -- cgit v1.2.3 From c1842d6150c4efe1d01e7a8cf86c63aec6223486 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 4 Aug 2008 16:00:43 +0800 Subject: iwlwifi: fix unhandled interrupt when HW rfkill is on This patch fixes unhandled interrupt when HW rfkill is on during devices start up. The behavior changes, now open is successful even when rfkill is on. This is to align with the situation when rfkill is set on after opening. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6503b3ac8d6..b8407d5704a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2232,17 +2232,16 @@ static int __iwl4965_up(struct iwl_priv *priv) } /* If platform's RF_KILL switch is NOT set to KILL */ - if (iwl_read32(priv, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) + if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) clear_bit(STATUS_RF_KILL_HW, &priv->status); else set_bit(STATUS_RF_KILL_HW, &priv->status); - if (!test_bit(STATUS_IN_SUSPEND, &priv->status) && - iwl_is_rfkill(priv)) { + if (iwl_is_rfkill(priv)) { + iwl4965_enable_interrupts(priv); IWL_WARNING("Radio disabled by %s RF Kill switch\n", test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW"); - return -ENODEV; + return 0; } iwl_write32(priv, CSR_INT, 0xFFFFFFFF); @@ -2278,11 +2277,6 @@ static int __iwl4965_up(struct iwl_priv *priv) memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, priv->ucode_data.len); - /* We return success when we resume from suspend and rf_kill is on. */ - if (test_bit(STATUS_RF_KILL_HW, &priv->status) || - test_bit(STATUS_RF_KILL_SW, &priv->status)) - return 0; - for (i = 0; i < MAX_HW_RESTARTS; i++) { iwl_clear_stations_table(priv); @@ -2651,6 +2645,9 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) if (ret) goto out_release_irq; + if (iwl_is_rfkill(priv)) + goto out; + IWL_DEBUG_INFO("Start UP work done.\n"); if (test_bit(STATUS_IN_SUSPEND, &priv->status)) @@ -2670,6 +2667,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) } } +out: priv->is_open = 1; IWL_DEBUG_MAC80211("leave\n"); return 0; -- cgit v1.2.3 From 14652562364dad636ddce2cd11e71702ca21bfbd Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 4 Aug 2008 16:00:46 +0800 Subject: iwlwifi: decrement rx skb counter in scan abort handler This patch decrements rx skb counter in scan abort handler. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-scan.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 5a00ac23e2d..9bb6adb28b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -202,6 +202,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) clear_bit(STATUS_SCAN_HW, &priv->status); } + priv->alloc_rxb_skb--; dev_kfree_skb_any(cmd.meta.u.skb); return ret; -- cgit v1.2.3 From 2d3db679511be102741cb2d5f8c2b8a1ededdee7 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 4 Aug 2008 16:00:47 +0800 Subject: iwlwifi: grap nic access before accessing periphery registers We need to grap nic access before accessing periphery registers. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index c5b104fd149..f3d139b663e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -241,9 +241,11 @@ static void iwl5000_nic_config(struct iwl_priv *priv) * (PCIe power is lost before PERST# is asserted), * causing ME FW to lose ownership and not being able to obtain it back. */ - iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, + iwl_grab_nic_access(priv); + iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); + iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); } -- cgit v1.2.3 From 3e2236c108792c3afbbfbe3f373ee7fdd68eda8e Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 4 Aug 2008 16:00:48 +0800 Subject: iwl3945: fix merge mistake for packet injection We should allow packets transmission in monitor mode for 3945. The patch fixes a merge error with 2.6.26 kernel. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index eb41b02b506..444847ab1b5 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6589,12 +6589,6 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) IWL_DEBUG_MAC80211("enter\n"); - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { - IWL_DEBUG_MAC80211("leave - monitor\n"); - dev_kfree_skb_any(skb); - return 0; - } - IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate); -- cgit v1.2.3 From fca082c9f1e11ec07efa8d2f9f13688521253f36 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 4 Aug 2008 16:36:20 -0700 Subject: Revert "[SCSI] extend the last_sector_bug flag to cover more sectors" This reverts commit 2b142900784c6e38c8d39fa57d5f95ef08e735d8, since it seems to break some other USB storage devices (at least a JMicron USB to ATA bridge). As such, while it apparently fixes some cardreaders, it would need to be made conditional on the exact reader it fixes in order to avoid causing regressions. Cc: Alan Jenkins Cc: James Bottomley Signed-off-by: Linus Torvalds --- drivers/scsi/sd.c | 21 ++++++--------------- drivers/scsi/sd.h | 6 ------ 2 files changed, 6 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e5e7d785645..8e08d51a0f0 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -375,7 +375,6 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) struct gendisk *disk = rq->rq_disk; struct scsi_disk *sdkp; sector_t block = rq->sector; - sector_t threshold; unsigned int this_count = rq->nr_sectors; unsigned int timeout = sdp->timeout; int ret; @@ -423,21 +422,13 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) } /* - * Some SD card readers can't handle multi-sector accesses which touch - * the last one or two hardware sectors. Split accesses as needed. + * Some devices (some sdcards for one) don't like it if the + * last sector gets read in a larger then 1 sector read. */ - threshold = get_capacity(disk) - SD_LAST_BUGGY_SECTORS * - (sdp->sector_size / 512); - - if (unlikely(sdp->last_sector_bug && block + this_count > threshold)) { - if (block < threshold) { - /* Access up to the threshold but not beyond */ - this_count = threshold - block; - } else { - /* Access only a single hardware sector */ - this_count = sdp->sector_size / 512; - } - } + if (unlikely(sdp->last_sector_bug && + rq->nr_sectors > sdp->sector_size / 512 && + block + this_count == get_capacity(disk))) + this_count -= sdp->sector_size / 512; SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n", (unsigned long long)block)); diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 95b9f06534d..550b2f70a1f 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -31,12 +31,6 @@ */ #define SD_BUF_SIZE 512 -/* - * Number of sectors at the end of the device to avoid multi-sector - * accesses to in the case of last_sector_bug - */ -#define SD_LAST_BUGGY_SECTORS 8 - struct scsi_disk { struct scsi_driver *driver; /* always &sd_template */ struct scsi_device *device; -- cgit v1.2.3 From 5aa6cf302c2758702348aab7457e516d3a5121b9 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 4 Aug 2008 13:41:10 -0700 Subject: spi: S3C24XX: reset register status on resume. Fix a bug in the spi_s3c24xx driver where it does not reset the registers of the hardware when resuming from suspend (this block has been reset over suspend). Signed-off-by: Ben Dooks Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/spi/spi_s3c24xx.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c index 1c643c9e1f1..21661c7959c 100644 --- a/drivers/spi/spi_s3c24xx.c +++ b/drivers/spi/spi_s3c24xx.c @@ -236,6 +236,19 @@ static irqreturn_t s3c24xx_spi_irq(int irq, void *dev) return IRQ_HANDLED; } +static void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw) +{ + /* for the moment, permanently enable the clock */ + + clk_enable(hw->clk); + + /* program defaults into the registers */ + + writeb(0xff, hw->regs + S3C2410_SPPRE); + writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN); + writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON); +} + static int __init s3c24xx_spi_probe(struct platform_device *pdev) { struct s3c2410_spi_info *pdata; @@ -327,15 +340,7 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev) goto err_no_clk; } - /* for the moment, permanently enable the clock */ - - clk_enable(hw->clk); - - /* program defaults into the registers */ - - writeb(0xff, hw->regs + S3C2410_SPPRE); - writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN); - writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON); + s3c24xx_spi_initialsetup(hw); /* setup any gpio we can */ @@ -415,7 +420,7 @@ static int s3c24xx_spi_resume(struct platform_device *pdev) { struct s3c24xx_spi *hw = platform_get_drvdata(pdev); - clk_enable(hw->clk); + s3c24xx_spi_initialsetup(hw); return 0; } -- cgit v1.2.3 From dc329442b9fd365bec95718013586c07ff600c34 Mon Sep 17 00:00:00 2001 From: Gerard Kam Date: Mon, 4 Aug 2008 13:41:12 -0700 Subject: atmel_spi: fix hang due to missed interrupt For some time my at91sam9260 board with JFFS2 on serial flash (m25p80) would hang when accessing the serial flash and SPI bus. Slowing the SPI clock down to 9 MHz reduced the occurrence of the hang from "always" during boot to a nuisance level that allowed other SW development to continue. Finally had to address this issue when an application stresses the I/O to always cause a hang. Hang seems to be caused by a missed SPI interrupt, so that the task ends up waiting forever after calling spi_sync(). The fix has 2 parts. First is to halt the DMA engine before the "current" PDC registers are loaded. This ensures that the "next" registers are loaded before the DMA operation takes off. The second part of the fix is a kludge that adds a "completion" interrupt in case the ENDRX interrupt for the last segment of the DMA chaining operation was missed. The patch allows the SPI clock for the serial flash to be increased from 9 MHz to 15 MHz (or more?). No hangs or SPI overruns were encountered. Haavard: while this patch does indeed improve things, I still see overruns and CRC errors on my NGW100 board when running the DataFlash at 10 MHz. However, I think some improvement is better than nothing, so I'm passing this on for inclusion in 2.6.27. Signed-off-by: Gerard Kam Signed-off-by: Haavard Skinnemoen Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/spi/atmel_spi.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index 0c716566085..95190c619c1 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -184,7 +184,8 @@ static void atmel_spi_next_xfer(struct spi_master *master, { struct atmel_spi *as = spi_master_get_devdata(master); struct spi_transfer *xfer; - u32 len, remaining, total; + u32 len, remaining; + u32 ieval; dma_addr_t tx_dma, rx_dma; if (!as->current_transfer) @@ -197,6 +198,8 @@ static void atmel_spi_next_xfer(struct spi_master *master, xfer = NULL; if (xfer) { + spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); + len = xfer->len; atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len); remaining = xfer->len - len; @@ -234,6 +237,8 @@ static void atmel_spi_next_xfer(struct spi_master *master, as->next_transfer = xfer; if (xfer) { + u32 total; + total = len; atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len); as->next_remaining_bytes = total - len; @@ -250,9 +255,11 @@ static void atmel_spi_next_xfer(struct spi_master *master, " next xfer %p: len %u tx %p/%08x rx %p/%08x\n", xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, xfer->rx_buf, xfer->rx_dma); + ieval = SPI_BIT(ENDRX) | SPI_BIT(OVRES); } else { spi_writel(as, RNCR, 0); spi_writel(as, TNCR, 0); + ieval = SPI_BIT(RXBUFF) | SPI_BIT(ENDRX) | SPI_BIT(OVRES); } /* REVISIT: We're waiting for ENDRX before we start the next @@ -265,7 +272,7 @@ static void atmel_spi_next_xfer(struct spi_master *master, * * It should be doable, though. Just not now... */ - spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES)); + spi_writel(as, IER, ieval); spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN)); } @@ -396,7 +403,7 @@ atmel_spi_interrupt(int irq, void *dev_id) ret = IRQ_HANDLED; - spi_writel(as, IDR, (SPI_BIT(ENDTX) | SPI_BIT(ENDRX) + spi_writel(as, IDR, (SPI_BIT(RXBUFF) | SPI_BIT(ENDRX) | SPI_BIT(OVRES))); /* @@ -418,7 +425,7 @@ atmel_spi_interrupt(int irq, void *dev_id) if (xfer->delay_usecs) udelay(xfer->delay_usecs); - dev_warn(master->dev.parent, "fifo overrun (%u/%u remaining)\n", + dev_warn(master->dev.parent, "overrun (%u/%u remaining)\n", spi_readl(as, TCR), spi_readl(as, RCR)); /* @@ -442,7 +449,7 @@ atmel_spi_interrupt(int irq, void *dev_id) spi_readl(as, SR); atmel_spi_msg_done(master, as, msg, -EIO, 0); - } else if (pending & SPI_BIT(ENDRX)) { + } else if (pending & (SPI_BIT(RXBUFF) | SPI_BIT(ENDRX))) { ret = IRQ_HANDLED; spi_writel(as, IDR, pending); -- cgit v1.2.3 From c2d5cedadcd3976cfc1fa5590e3a73a059c6401a Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Sat, 2 Aug 2008 21:10:23 +0800 Subject: drivers/char/efirtc.c: removed duplicated #include Removed duplicated include in drivers/char/efirtc.c. Signed-off-by: Huang Weiyi Signed-off-by: Linus Torvalds --- drivers/char/efirtc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c index 67fbd7aab5d..34d15d54823 100644 --- a/drivers/char/efirtc.c +++ b/drivers/char/efirtc.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include -- cgit v1.2.3 From b1cbefe5d5fc2d4a6109961d914027172ce8e152 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 4 Aug 2008 17:22:11 +0100 Subject: blackfin: Fix compile failure in tty code Blackfin peers into the ldisc in an odd way for IRDA snooping which therefore got missed. Simple enough fix. Closes bug #11233 Signed-off-by: Linus Torvalds --- drivers/serial/bfin_5xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 9d8543762a3..efcd44344fb 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -817,7 +817,7 @@ static void bfin_serial_set_ldisc(struct uart_port *port) if (line >= port->info->port.tty->driver->num) return; - switch (port->info->port.tty->ldisc.num) { + switch (port->info->port.tty->termios->c_line) { case N_IRDA: val = UART_GET_GCTL(&bfin_serial_ports[line]); val |= (IREN | RPOLC); -- cgit v1.2.3 From d7283353221e73a793847252d063ff9186885160 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 4 Aug 2008 17:21:18 +0100 Subject: cris: Fixup compile problems It now compiles with the tty changes but isn't tested (which has to be better than not compiling.. Closes bug #11218 Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/serial/crisv10.c | 79 ++++++++++++++++++++++++------------------------ drivers/serial/crisv10.h | 3 +- 2 files changed, 42 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c index 8249ac49055..bf94a770bb4 100644 --- a/drivers/serial/crisv10.c +++ b/drivers/serial/crisv10.c @@ -234,7 +234,7 @@ unsigned long r_alt_ser_baudrate_shadow = 0; static struct e100_serial rs_table[] = { { .baud = DEF_BAUD, - .port = (unsigned char *)R_SERIAL0_CTRL, + .ioport = (unsigned char *)R_SERIAL0_CTRL, .irq = 1U << 12, /* uses DMA 6 and 7 */ .oclrintradr = R_DMA_CH6_CLR_INTR, .ofirstadr = R_DMA_CH6_FIRST, @@ -288,7 +288,7 @@ static struct e100_serial rs_table[] = { }, /* ttyS0 */ #ifndef CONFIG_SVINTO_SIM { .baud = DEF_BAUD, - .port = (unsigned char *)R_SERIAL1_CTRL, + .ioport = (unsigned char *)R_SERIAL1_CTRL, .irq = 1U << 16, /* uses DMA 8 and 9 */ .oclrintradr = R_DMA_CH8_CLR_INTR, .ofirstadr = R_DMA_CH8_FIRST, @@ -344,7 +344,7 @@ static struct e100_serial rs_table[] = { }, /* ttyS1 */ { .baud = DEF_BAUD, - .port = (unsigned char *)R_SERIAL2_CTRL, + .ioport = (unsigned char *)R_SERIAL2_CTRL, .irq = 1U << 4, /* uses DMA 2 and 3 */ .oclrintradr = R_DMA_CH2_CLR_INTR, .ofirstadr = R_DMA_CH2_FIRST, @@ -398,7 +398,7 @@ static struct e100_serial rs_table[] = { }, /* ttyS2 */ { .baud = DEF_BAUD, - .port = (unsigned char *)R_SERIAL3_CTRL, + .ioport = (unsigned char *)R_SERIAL3_CTRL, .irq = 1U << 8, /* uses DMA 4 and 5 */ .oclrintradr = R_DMA_CH4_CLR_INTR, .ofirstadr = R_DMA_CH4_FIRST, @@ -939,7 +939,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] = /* Output */ #define E100_RTS_GET(info) ((info)->rx_ctrl & E100_RTS_MASK) /* Input */ -#define E100_CTS_GET(info) ((info)->port[REG_STATUS] & E100_CTS_MASK) +#define E100_CTS_GET(info) ((info)->ioport[REG_STATUS] & E100_CTS_MASK) /* These are typically PA or PB and 0 means 0V, 1 means 3.3V */ /* Is an output */ @@ -1092,7 +1092,7 @@ e100_rts(struct e100_serial *info, int set) local_irq_save(flags); info->rx_ctrl &= ~E100_RTS_MASK; info->rx_ctrl |= (set ? 0 : E100_RTS_MASK); /* RTS is active low */ - info->port[REG_REC_CTRL] = info->rx_ctrl; + info->ioport[REG_REC_CTRL] = info->rx_ctrl; local_irq_restore(flags); #ifdef SERIAL_DEBUG_IO printk("ser%i rts %i\n", info->line, set); @@ -1142,7 +1142,7 @@ e100_disable_rx(struct e100_serial *info) { #ifndef CONFIG_SVINTO_SIM /* disable the receiver */ - info->port[REG_REC_CTRL] = + info->ioport[REG_REC_CTRL] = (info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); #endif } @@ -1152,7 +1152,7 @@ e100_enable_rx(struct e100_serial *info) { #ifndef CONFIG_SVINTO_SIM /* enable the receiver */ - info->port[REG_REC_CTRL] = + info->ioport[REG_REC_CTRL] = (info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); #endif } @@ -1490,7 +1490,7 @@ rs_stop(struct tty_struct *tty) xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); } - *((unsigned long *)&info->port[REG_XOFF]) = xoff; + *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; local_irq_restore(flags); } } @@ -1513,7 +1513,7 @@ rs_start(struct tty_struct *tty) xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); } - *((unsigned long *)&info->port[REG_XOFF]) = xoff; + *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; if (!info->uses_dma_out && info->xmit.head != info->xmit.tail && info->xmit.buf) e100_enable_serial_tx_ready_irq(info); @@ -1888,7 +1888,7 @@ static void receive_chars_dma(struct e100_serial *info) handle_all_descr_data(info); /* Read the status register to detect errors */ - rstat = info->port[REG_STATUS]; + rstat = info->ioport[REG_STATUS]; if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) { DFLOW(DEBUG_LOG(info->line, "XOFF detect stat %x\n", rstat)); } @@ -1897,7 +1897,7 @@ static void receive_chars_dma(struct e100_serial *info) /* If we got an error, we must reset it by reading the * data_in field */ - unsigned char data = info->port[REG_DATA]; + unsigned char data = info->ioport[REG_DATA]; PROCSTAT(ser_stat[info->line].errors_cnt++); DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n", @@ -2077,7 +2077,7 @@ static int force_eop_if_needed(struct e100_serial *info) /* We check data_avail bit to determine if data has * arrived since last time */ - unsigned char rstat = info->port[REG_STATUS]; + unsigned char rstat = info->ioport[REG_STATUS]; /* error or datavail? */ if (rstat & SER_ERROR_MASK) { @@ -2096,7 +2096,7 @@ static int force_eop_if_needed(struct e100_serial *info) TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n", rstat | (info->line << 8))); /* Read data to clear status flags */ - (void)info->port[REG_DATA]; + (void)info->ioport[REG_DATA]; info->forced_eop = 0; START_FLUSH_FAST_TIMER(info, "magic"); @@ -2296,7 +2296,7 @@ struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info) } /* Read data and status at the same time */ - data_read = *((unsigned long *)&info->port[REG_DATA_STATUS32]); + data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]); more_data: if (data_read & IO_MASK(R_SERIAL0_READ, xoff_detect) ) { DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0)); @@ -2391,7 +2391,7 @@ more_data: info->icount.rx++; - data_read = *((unsigned long *)&info->port[REG_DATA_STATUS32]); + data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]); if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) { DEBUG_LOG(info->line, "ser_rx %c in loop\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read)); goto more_data; @@ -2413,7 +2413,7 @@ static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info) return handle_ser_rx_interrupt_no_dma(info); } /* DMA is used */ - rstat = info->port[REG_STATUS]; + rstat = info->ioport[REG_STATUS]; if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) { DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0)); } @@ -2426,7 +2426,7 @@ static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info) /* If we got an error, we must reset it by reading the * data_in field */ - data = info->port[REG_DATA]; + data = info->ioport[REG_DATA]; DINTR1(DEBUG_LOG(info->line, "ser_rx! %c\n", data)); DINTR1(DEBUG_LOG(info->line, "ser_rx err stat %02X\n", rstat)); if (!data && (rstat & SER_FRAMING_ERR_MASK)) { @@ -2528,10 +2528,10 @@ static void handle_ser_tx_interrupt(struct e100_serial *info) unsigned char rstat; DFLOW(DEBUG_LOG(info->line, "tx_int: xchar 0x%02X\n", info->x_char)); local_irq_save(flags); - rstat = info->port[REG_STATUS]; + rstat = info->ioport[REG_STATUS]; DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat)); - info->port[REG_TR_DATA] = info->x_char; + info->ioport[REG_TR_DATA] = info->x_char; info->icount.tx++; info->x_char = 0; /* We must enable since it is disabled in ser_interrupt */ @@ -2545,7 +2545,7 @@ static void handle_ser_tx_interrupt(struct e100_serial *info) /* We only use normal tx interrupt when sending x_char */ DFLOW(DEBUG_LOG(info->line, "tx_int: xchar sent\n", 0)); local_irq_save(flags); - rstat = info->port[REG_STATUS]; + rstat = info->ioport[REG_STATUS]; DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat)); e100_disable_serial_tx_ready_irq(info); if (info->port.tty->stopped) @@ -2573,7 +2573,7 @@ static void handle_ser_tx_interrupt(struct e100_serial *info) DINTR2(DEBUG_LOG(info->line, "tx_int %c\n", info->xmit.buf[info->xmit.tail])); /* Send a byte, rs485 timing is critical so turn of ints */ local_irq_save(flags); - info->port[REG_TR_DATA] = info->xmit.buf[info->xmit.tail]; + info->ioport[REG_TR_DATA] = info->xmit.buf[info->xmit.tail]; info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1); info->icount.tx++; if (info->xmit.head == info->xmit.tail) { @@ -2848,7 +2848,7 @@ startup(struct e100_serial * info) /* dummy read to reset any serial errors */ - (void)info->port[REG_DATA]; + (void)info->ioport[REG_DATA]; /* enable the interrupts */ if (info->uses_dma_out) @@ -2897,7 +2897,7 @@ shutdown(struct e100_serial * info) /* shut down the transmitter and receiver */ DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line)); e100_disable_rx(info); - info->port[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40); + info->ioport[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40); /* disable interrupts, reset dma channels */ if (info->uses_dma_in) { @@ -2968,7 +2968,7 @@ change_speed(struct e100_serial *info) if (!info->port.tty || !info->port.tty->termios) return; - if (!info->port) + if (!info->ioport) return; cflag = info->port.tty->termios->c_cflag; @@ -3037,7 +3037,7 @@ change_speed(struct e100_serial *info) info->baud = cflag_to_baud(cflag); #ifndef CONFIG_SVINTO_SIM - info->port[REG_BAUD] = cflag_to_etrax_baud(cflag); + info->ioport[REG_BAUD] = cflag_to_etrax_baud(cflag); #endif /* CONFIG_SVINTO_SIM */ } @@ -3097,8 +3097,8 @@ change_speed(struct e100_serial *info) /* actually write the control regs to the hardware */ - info->port[REG_TR_CTRL] = info->tx_ctrl; - info->port[REG_REC_CTRL] = info->rx_ctrl; + info->ioport[REG_TR_CTRL] = info->tx_ctrl; + info->ioport[REG_REC_CTRL] = info->rx_ctrl; xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty)); xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); if (info->port.tty->termios->c_iflag & IXON ) { @@ -3107,7 +3107,7 @@ change_speed(struct e100_serial *info) xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); } - *((unsigned long *)&info->port[REG_XOFF]) = xoff; + *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; local_irq_restore(flags); #endif /* !CONFIG_SVINTO_SIM */ @@ -3156,7 +3156,7 @@ static int rs_raw_write(struct tty_struct *tty, #ifdef SERIAL_DEBUG_DATA if (info->line == SERIAL_DEBUG_LINE) printk("rs_raw_write (%d), status %d\n", - count, info->port[REG_STATUS]); + count, info->ioport[REG_STATUS]); #endif #ifdef CONFIG_SVINTO_SIM @@ -3427,7 +3427,7 @@ get_serial_info(struct e100_serial * info, memset(&tmp, 0, sizeof(tmp)); tmp.type = info->type; tmp.line = info->line; - tmp.port = (int)info->port; + tmp.port = (int)info->ioport; tmp.irq = info->irq; tmp.flags = info->flags; tmp.baud_base = info->baud_base; @@ -3557,14 +3557,14 @@ char *get_control_state_str(int MLines, char *s) } #endif -static void +static int rs_break(struct tty_struct *tty, int break_state) { struct e100_serial *info = (struct e100_serial *)tty->driver_data; unsigned long flags; - if (!info->port) - return; + if (!info->ioport) + return -EIO; local_irq_save(flags); if (break_state == -1) { @@ -3575,8 +3575,9 @@ rs_break(struct tty_struct *tty, int break_state) /* Set bit 7 (txd) and 6 (tr_enable) */ info->tx_ctrl |= (0x80 | 0x40); } - info->port[REG_TR_CTRL] = info->tx_ctrl; + info->ioport[REG_TR_CTRL] = info->tx_ctrl; local_irq_restore(flags); + return 0; } static int @@ -4231,9 +4232,9 @@ static int line_info(char *buf, struct e100_serial *info) unsigned long tmp; ret = sprintf(buf, "%d: uart:E100 port:%lX irq:%d", - info->line, (unsigned long)info->port, info->irq); + info->line, (unsigned long)info->ioport, info->irq); - if (!info->port || (info->type == PORT_UNKNOWN)) { + if (!info->ioport || (info->type == PORT_UNKNOWN)) { ret += sprintf(buf+ret, "\n"); return ret; } @@ -4281,7 +4282,7 @@ static int line_info(char *buf, struct e100_serial *info) } { - unsigned char rstat = info->port[REG_STATUS]; + unsigned char rstat = info->ioport[REG_STATUS]; if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) ret += sprintf(buf+ret, " xoff_detect:1"); } @@ -4502,7 +4503,7 @@ rs_init(void) if (info->enabled) { printk(KERN_INFO "%s%d at 0x%x is a builtin UART with DMA\n", - serial_driver->name, info->line, (unsigned int)info->port); + serial_driver->name, info->line, (unsigned int)info->ioport); } } #ifdef CONFIG_ETRAX_FAST_TIMER diff --git a/drivers/serial/crisv10.h b/drivers/serial/crisv10.h index ccd0f32b737..e3c5c8c3c09 100644 --- a/drivers/serial/crisv10.h +++ b/drivers/serial/crisv10.h @@ -36,8 +36,9 @@ struct etrax_recv_buffer { }; struct e100_serial { + struct tty_port port; int baud; - volatile u8 *port; /* R_SERIALx_CTRL */ + volatile u8 *ioport; /* R_SERIALx_CTRL */ u32 irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ /* Output registers */ -- cgit v1.2.3 From d5cae364148088911bdf007a8aaefb46a92f16f7 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 4 Aug 2008 17:47:07 +0100 Subject: vt: Deadlock workaround 2.6.26 corrected the mutex locking on tty resizing to fix the case where you could get the tty/vt sizing out of sync. That turns out to have a deadlock. The actual fix is really major and I've got it lined up as part of the ops changes for 2.6.28 so for 2.6.26/2.6.27 it is safer to reintroduce this ages old minor bug. Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/char/vt.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 82a51f38a54..1bc00c9d860 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -916,7 +916,6 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) ws.ws_col = vc->vc_cols; ws.ws_ypixel = vc->vc_scan_lines; - mutex_lock(&vc->vc_tty->termios_mutex); spin_lock_irq(&vc->vc_tty->ctrl_lock); if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col)) pgrp = get_pid(vc->vc_tty->pgrp); @@ -926,7 +925,6 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) put_pid(pgrp); } *cws = ws; - mutex_unlock(&vc->vc_tty->termios_mutex); } if (CON_IS_VISIBLE(vc)) -- cgit v1.2.3 From 670d59c0ae31a872341785b1d93add284c1653ff Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 4 Aug 2008 17:53:22 +0100 Subject: ar7_wdt watchdog driver: Fix locking Use unlocked_ioctl Remove semaphores Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/watchdog/ar7_wdt.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c index 2eb48c0df32..ef7b0d67095 100644 --- a/drivers/watchdog/ar7_wdt.c +++ b/drivers/watchdog/ar7_wdt.c @@ -69,7 +69,8 @@ struct ar7_wdt { u32 prescale; }; -static struct semaphore open_semaphore; +static unsigned long wdt_is_open; +static spinlock_t wdt_lock; static unsigned expect_close; /* XXX currently fixed, allows max margin ~68.72 secs */ @@ -154,8 +155,10 @@ static void ar7_wdt_update_margin(int new_margin) u32 change; change = new_margin * (ar7_vbus_freq() / prescale_value); - if (change < 1) change = 1; - if (change > 0xffff) change = 0xffff; + if (change < 1) + change = 1; + if (change > 0xffff) + change = 0xffff; ar7_wdt_change(change); margin = change * prescale_value / ar7_vbus_freq(); printk(KERN_INFO DRVNAME @@ -179,7 +182,7 @@ static void ar7_wdt_disable_wdt(void) static int ar7_wdt_open(struct inode *inode, struct file *file) { /* only allow one at a time */ - if (down_trylock(&open_semaphore)) + if (test_and_set_bit(0, &wdt_is_open)) return -EBUSY; ar7_wdt_enable_wdt(); expect_close = 0; @@ -195,9 +198,7 @@ static int ar7_wdt_release(struct inode *inode, struct file *file) "will not disable the watchdog timer\n"); else if (!nowayout) ar7_wdt_disable_wdt(); - - up(&open_semaphore); - + clear_bit(0, &wdt_is_open); return 0; } @@ -222,7 +223,9 @@ static ssize_t ar7_wdt_write(struct file *file, const char *data, if (len) { size_t i; + spin_lock(&wdt_lock); ar7_wdt_kick(1); + spin_unlock(&wdt_lock); expect_close = 0; for (i = 0; i < len; ++i) { @@ -237,8 +240,8 @@ static ssize_t ar7_wdt_write(struct file *file, const char *data, return len; } -static int ar7_wdt_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long ar7_wdt_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) { static struct watchdog_info ident = { .identity = LONGNAME, @@ -269,8 +272,10 @@ static int ar7_wdt_ioctl(struct inode *inode, struct file *file, if (new_margin < 1) return -EINVAL; + spin_lock(&wdt_lock); ar7_wdt_update_margin(new_margin); ar7_wdt_kick(1); + spin_unlock(&wdt_lock); case WDIOC_GETTIMEOUT: if (put_user(margin, (int *)arg)) @@ -282,7 +287,7 @@ static int ar7_wdt_ioctl(struct inode *inode, struct file *file, static const struct file_operations ar7_wdt_fops = { .owner = THIS_MODULE, .write = ar7_wdt_write, - .ioctl = ar7_wdt_ioctl, + .unlocked_ioctl = ar7_wdt_ioctl, .open = ar7_wdt_open, .release = ar7_wdt_release, }; @@ -297,6 +302,8 @@ static int __init ar7_wdt_init(void) { int rc; + spin_lock_init(&wdt_lock); + ar7_wdt_get_regs(); if (!request_mem_region(ar7_regs_wdt, sizeof(struct ar7_wdt), @@ -312,8 +319,6 @@ static int __init ar7_wdt_init(void) ar7_wdt_prescale(prescale_value); ar7_wdt_update_margin(margin); - sema_init(&open_semaphore, 1); - rc = register_reboot_notifier(&ar7_wdt_notifier); if (rc) { printk(KERN_ERR DRVNAME -- cgit v1.2.3 From d6547378df1c11bc6790b87abedb3526ded40ef9 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 4 Aug 2008 17:54:01 +0100 Subject: it8712f_wdt: Locking and coding style Signed-off-by: Andrew Morton Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/watchdog/it8712f_wdt.c | 77 +++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c index 445b7e81211..51bfd572183 100644 --- a/drivers/watchdog/it8712f_wdt.c +++ b/drivers/watchdog/it8712f_wdt.c @@ -30,9 +30,8 @@ #include #include #include - -#include -#include +#include +#include #define NAME "it8712f_wdt" @@ -50,7 +49,7 @@ static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); -static struct semaphore it8712f_wdt_sem; +static unsigned long wdt_open; static unsigned expect_close; static spinlock_t io_lock; static unsigned char revision; @@ -86,22 +85,19 @@ static unsigned short address; #define WDT_OUT_PWROK 0x10 #define WDT_OUT_KRST 0x40 -static int -superio_inb(int reg) +static int superio_inb(int reg) { outb(reg, REG); return inb(VAL); } -static void -superio_outb(int val, int reg) +static void superio_outb(int val, int reg) { outb(reg, REG); outb(val, VAL); } -static int -superio_inw(int reg) +static int superio_inw(int reg) { int val; outb(reg++, REG); @@ -111,15 +107,13 @@ superio_inw(int reg) return val; } -static inline void -superio_select(int ldn) +static inline void superio_select(int ldn) { outb(LDN, REG); outb(ldn, VAL); } -static inline void -superio_enter(void) +static inline void superio_enter(void) { spin_lock(&io_lock); outb(0x87, REG); @@ -128,22 +122,19 @@ superio_enter(void) outb(0x55, REG); } -static inline void -superio_exit(void) +static inline void superio_exit(void) { outb(0x02, REG); outb(0x02, VAL); spin_unlock(&io_lock); } -static inline void -it8712f_wdt_ping(void) +static inline void it8712f_wdt_ping(void) { inb(address); } -static void -it8712f_wdt_update_margin(void) +static void it8712f_wdt_update_margin(void) { int config = WDT_OUT_KRST | WDT_OUT_PWROK; int units = margin; @@ -165,8 +156,7 @@ it8712f_wdt_update_margin(void) superio_outb(units, WDT_TIMEOUT); } -static int -it8712f_wdt_get_status(void) +static int it8712f_wdt_get_status(void) { if (superio_inb(WDT_CONTROL) & 0x01) return WDIOF_CARDRESET; @@ -174,8 +164,7 @@ it8712f_wdt_get_status(void) return 0; } -static void -it8712f_wdt_enable(void) +static void it8712f_wdt_enable(void) { printk(KERN_DEBUG NAME ": enabling watchdog timer\n"); superio_enter(); @@ -190,8 +179,7 @@ it8712f_wdt_enable(void) it8712f_wdt_ping(); } -static void -it8712f_wdt_disable(void) +static void it8712f_wdt_disable(void) { printk(KERN_DEBUG NAME ": disabling watchdog timer\n"); @@ -207,8 +195,7 @@ it8712f_wdt_disable(void) superio_exit(); } -static int -it8712f_wdt_notify(struct notifier_block *this, +static int it8712f_wdt_notify(struct notifier_block *this, unsigned long code, void *unused) { if (code == SYS_HALT || code == SYS_POWER_OFF) @@ -222,9 +209,8 @@ static struct notifier_block it8712f_wdt_notifier = { .notifier_call = it8712f_wdt_notify, }; -static ssize_t -it8712f_wdt_write(struct file *file, const char __user *data, - size_t len, loff_t *ppos) +static ssize_t it8712f_wdt_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) { /* check for a magic close character */ if (len) { @@ -245,9 +231,8 @@ it8712f_wdt_write(struct file *file, const char __user *data, return len; } -static int -it8712f_wdt_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { void __user *argp = (void __user *)arg; int __user *p = argp; @@ -302,19 +287,16 @@ it8712f_wdt_ioctl(struct inode *inode, struct file *file, } } -static int -it8712f_wdt_open(struct inode *inode, struct file *file) +static int it8712f_wdt_open(struct inode *inode, struct file *file) { /* only allow one at a time */ - if (down_trylock(&it8712f_wdt_sem)) + if (test_and_set_bit(0, &wdt_open)) return -EBUSY; it8712f_wdt_enable(); - return nonseekable_open(inode, file); } -static int -it8712f_wdt_release(struct inode *inode, struct file *file) +static int it8712f_wdt_release(struct inode *inode, struct file *file) { if (expect_close != 42) { printk(KERN_WARNING NAME @@ -324,7 +306,7 @@ it8712f_wdt_release(struct inode *inode, struct file *file) it8712f_wdt_disable(); } expect_close = 0; - up(&it8712f_wdt_sem); + clear_bit(0, &wdt_open); return 0; } @@ -333,7 +315,7 @@ static const struct file_operations it8712f_wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = it8712f_wdt_write, - .ioctl = it8712f_wdt_ioctl, + .unlocked_ioctl = it8712f_wdt_ioctl, .open = it8712f_wdt_open, .release = it8712f_wdt_release, }; @@ -344,8 +326,7 @@ static struct miscdevice it8712f_wdt_miscdev = { .fops = &it8712f_wdt_fops, }; -static int __init -it8712f_wdt_find(unsigned short *address) +static int __init it8712f_wdt_find(unsigned short *address) { int err = -ENODEV; int chip_type; @@ -387,8 +368,7 @@ exit: return err; } -static int __init -it8712f_wdt_init(void) +static int __init it8712f_wdt_init(void) { int err = 0; @@ -404,8 +384,6 @@ it8712f_wdt_init(void) it8712f_wdt_disable(); - sema_init(&it8712f_wdt_sem, 1); - err = register_reboot_notifier(&it8712f_wdt_notifier); if (err) { printk(KERN_ERR NAME ": unable to register reboot notifier\n"); @@ -430,8 +408,7 @@ out: return err; } -static void __exit -it8712f_wdt_exit(void) +static void __exit it8712f_wdt_exit(void) { misc_deregister(&it8712f_wdt_miscdev); unregister_reboot_notifier(&it8712f_wdt_notifier); -- cgit v1.2.3 From 41dc8b72e37c514f7332cbc3f3dd864910c2a1fa Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 4 Aug 2008 17:54:46 +0100 Subject: s3c2410_wdt watchdog driver: Locking and coding style Kill off use of semaphores. Fix ioctl races and locking holes. From: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/watchdog/s3c2410_wdt.c | 148 ++++++++++++++++++++++------------------- 1 file changed, 80 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 98532c0e068..97b4a2e8eb0 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -46,9 +46,8 @@ #include #include #include - -#include -#include +#include +#include #include @@ -65,8 +64,8 @@ static int nowayout = WATCHDOG_NOWAYOUT; static int tmr_margin = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME; static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT; -static int soft_noboot = 0; -static int debug = 0; +static int soft_noboot; +static int debug; module_param(tmr_margin, int, 0); module_param(tmr_atboot, int, 0); @@ -74,24 +73,23 @@ module_param(nowayout, int, 0); module_param(soft_noboot, int, 0); module_param(debug, int, 0); -MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. default=" __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME) ")"); - -MODULE_PARM_DESC(tmr_atboot, "Watchdog is started at boot time if set to 1, default=" __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT)); - -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); - +MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. default=" + __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME) ")"); +MODULE_PARM_DESC(tmr_atboot, + "Watchdog is started at boot time if set to 1, default=" + __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT)); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, 0 to reboot (default depends on ONLY_TESTING)"); - MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug, (default 0)"); typedef enum close_state { CLOSE_STATE_NOT, - CLOSE_STATE_ALLOW=0x4021 + CLOSE_STATE_ALLOW = 0x4021 } close_state_t; -static DECLARE_MUTEX(open_lock); - +static unsigned long open_lock; static struct device *wdt_dev; /* platform device attached to */ static struct resource *wdt_mem; static struct resource *wdt_irq; @@ -99,38 +97,58 @@ static struct clk *wdt_clock; static void __iomem *wdt_base; static unsigned int wdt_count; static close_state_t allow_close; +static DEFINE_SPINLOCK(wdt_lock); /* watchdog control routines */ #define DBG(msg...) do { \ if (debug) \ printk(KERN_INFO msg); \ - } while(0) + } while (0) /* functions */ -static int s3c2410wdt_keepalive(void) +static void s3c2410wdt_keepalive(void) { + spin_lock(&wdt_lock); writel(wdt_count, wdt_base + S3C2410_WTCNT); - return 0; + spin_unlock(&wdt_lock); } -static int s3c2410wdt_stop(void) +static void __s3c2410wdt_stop(void) { unsigned long wtcon; + spin_lock(&wdt_lock); wtcon = readl(wdt_base + S3C2410_WTCON); wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN); writel(wtcon, wdt_base + S3C2410_WTCON); + spin_unlock(&wdt_lock); +} - return 0; +static void __s3c2410wdt_stop(void) +{ + unsigned long wtcon; + + wtcon = readl(wdt_base + S3C2410_WTCON); + wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN); + writel(wtcon, wdt_base + S3C2410_WTCON); +} + +static void s3c2410wdt_stop(void) +{ + spin_lock(&wdt_lock); + __s3c2410wdt_stop(); + spin_unlock(&wdt_lock); } -static int s3c2410wdt_start(void) +static void s3c2410wdt_start(void) { unsigned long wtcon; - s3c2410wdt_stop(); + spin_lock(&wdt_lock); + + __s3c2410wdt_stop(); wtcon = readl(wdt_base + S3C2410_WTCON); wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128; @@ -149,6 +167,7 @@ static int s3c2410wdt_start(void) writel(wdt_count, wdt_base + S3C2410_WTDAT); writel(wdt_count, wdt_base + S3C2410_WTCNT); writel(wtcon, wdt_base + S3C2410_WTCON); + spin_unlock(&wdt_lock); return 0; } @@ -211,7 +230,7 @@ static int s3c2410wdt_set_heartbeat(int timeout) static int s3c2410wdt_open(struct inode *inode, struct file *file) { - if(down_trylock(&open_lock)) + if (test_and_set_bit(0, &open_lock)) return -EBUSY; if (nowayout) @@ -231,15 +250,14 @@ static int s3c2410wdt_release(struct inode *inode, struct file *file) * Lock it in if it's a module and we set nowayout */ - if (allow_close == CLOSE_STATE_ALLOW) { + if (allow_close == CLOSE_STATE_ALLOW) s3c2410wdt_stop(); - } else { + else { dev_err(wdt_dev, "Unexpected close, not stopping watchdog\n"); s3c2410wdt_keepalive(); } - allow_close = CLOSE_STATE_NOT; - up(&open_lock); + clear_bit(0, &open_lock); return 0; } @@ -249,7 +267,7 @@ static ssize_t s3c2410wdt_write(struct file *file, const char __user *data, /* * Refresh the timer. */ - if(len) { + if (len) { if (!nowayout) { size_t i; @@ -265,7 +283,6 @@ static ssize_t s3c2410wdt_write(struct file *file, const char __user *data, allow_close = CLOSE_STATE_ALLOW; } } - s3c2410wdt_keepalive(); } return len; @@ -273,48 +290,41 @@ static ssize_t s3c2410wdt_write(struct file *file, const char __user *data, #define OPTIONS WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE -static struct watchdog_info s3c2410_wdt_ident = { +static const struct watchdog_info s3c2410_wdt_ident = { .options = OPTIONS, .firmware_version = 0, .identity = "S3C2410 Watchdog", }; -static int s3c2410wdt_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long s3c2410wdt_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { void __user *argp = (void __user *)arg; int __user *p = argp; int new_margin; switch (cmd) { - default: - return -ENOTTY; - - case WDIOC_GETSUPPORT: - return copy_to_user(argp, &s3c2410_wdt_ident, - sizeof(s3c2410_wdt_ident)) ? -EFAULT : 0; - - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user(0, p); - - case WDIOC_KEEPALIVE: - s3c2410wdt_keepalive(); - return 0; - - case WDIOC_SETTIMEOUT: - if (get_user(new_margin, p)) - return -EFAULT; - - if (s3c2410wdt_set_heartbeat(new_margin)) - return -EINVAL; - - s3c2410wdt_keepalive(); - return put_user(tmr_margin, p); - - case WDIOC_GETTIMEOUT: - return put_user(tmr_margin, p); + default: + return -ENOTTY; + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &s3c2410_wdt_ident, + sizeof(s3c2410_wdt_ident)) ? -EFAULT : 0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + case WDIOC_KEEPALIVE: + s3c2410wdt_keepalive(); + return 0; + case WDIOC_SETTIMEOUT: + if (get_user(new_margin, p)) + return -EFAULT; + if (s3c2410wdt_set_heartbeat(new_margin)) + return -EINVAL; + s3c2410wdt_keepalive(); + return put_user(tmr_margin, p); + case WDIOC_GETTIMEOUT: + return put_user(tmr_margin, p); } } @@ -324,7 +334,7 @@ static const struct file_operations s3c2410wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = s3c2410wdt_write, - .ioctl = s3c2410wdt_ioctl, + .unlocked_ioctl = s3c2410wdt_ioctl, .open = s3c2410wdt_open, .release = s3c2410wdt_release, }; @@ -411,14 +421,15 @@ static int s3c2410wdt_probe(struct platform_device *pdev) * not, try the default value */ if (s3c2410wdt_set_heartbeat(tmr_margin)) { - started = s3c2410wdt_set_heartbeat(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); + started = s3c2410wdt_set_heartbeat( + CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); - if (started == 0) { - dev_info(dev,"tmr_margin value out of range, default %d used\n", + if (started == 0) + dev_info(dev, + "tmr_margin value out of range, default %d used\n", CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); - } else { + else dev_info(dev, "default timer value is out of range, cannot start\n"); - } } ret = misc_register(&s3c2410wdt_miscdev); @@ -447,7 +458,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) (wtcon & S3C2410_WTCON_ENABLE) ? "" : "in", (wtcon & S3C2410_WTCON_RSTEN) ? "" : "dis", (wtcon & S3C2410_WTCON_INTEN) ? "" : "en"); - + return 0; err_clk: @@ -487,7 +498,7 @@ static int s3c2410wdt_remove(struct platform_device *dev) static void s3c2410wdt_shutdown(struct platform_device *dev) { - s3c2410wdt_stop(); + s3c2410wdt_stop(); } #ifdef CONFIG_PM @@ -540,7 +551,8 @@ static struct platform_driver s3c2410wdt_driver = { }; -static char banner[] __initdata = KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n"; +static char banner[] __initdata = + KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n"; static int __init watchdog_init(void) { -- cgit v1.2.3 From 9f2d1f0da766f84fdb96c9bd79ed0f97036635cb Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 4 Aug 2008 17:55:35 +0100 Subject: wdt: Cleanup and sort out locking and inb_p Signed-off-by: Andrew Morton Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/watchdog/wdt.c | 176 +++++++++++++------------- drivers/watchdog/wdt_pci.c | 300 ++++++++++++++++++++++++++------------------- 2 files changed, 265 insertions(+), 211 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c index 756fb15fdce..53a6b18bcb9 100644 --- a/drivers/watchdog/wdt.c +++ b/drivers/watchdog/wdt.c @@ -24,9 +24,10 @@ * Matt Crocker). * Alan Cox : Added wdt= boot option * Alan Cox : Cleaned up copy/user stuff - * Tim Hockin : Added insmod parameters, comment cleanup - * Parameterized timeout - * Tigran Aivazian : Restructured wdt_init() to handle failures + * Tim Hockin : Added insmod parameters, comment + * cleanup, parameterized timeout + * Tigran Aivazian : Restructured wdt_init() to handle + * failures * Joel Becker : Added WDIOC_GET/SETTIMEOUT * Matt Domsch : Added nowayout module option */ @@ -42,9 +43,9 @@ #include #include #include +#include +#include -#include -#include #include #include "wd501p.h" @@ -60,15 +61,19 @@ static char expect_close; static int heartbeat = WD_TIMO; static int wd_heartbeat; module_param(heartbeat, int, 0); -MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0 65535)) + if (t < 1 || t > 65535) return -EINVAL; heartbeat = t; @@ -200,7 +211,7 @@ static int wdt_get_status(int *status) new_status = inb_p(WDT_SR); spin_unlock_irqrestore(&wdt_lock, flags); - *status=0; + *status = 0; if (new_status & WDC_SR_ISOI0) *status |= WDIOF_EXTERN1; if (new_status & WDC_SR_ISII1) @@ -266,7 +277,7 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id) #ifdef CONFIG_WDT_501 if (!(status & WDC_SR_TGOOD)) - printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT)); + printk(KERN_CRIT "Overheat alarm.(%d)\n", inb_p(WDT_RT)); if (!(status & WDC_SR_PSUOVER)) printk(KERN_CRIT "PSU over voltage.\n"); if (!(status & WDC_SR_PSUUNDR)) @@ -304,9 +315,10 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id) * write of data will do, as we we don't define content meaning. */ -static ssize_t wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +static ssize_t wdt_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { - if(count) { + if (count) { if (!nowayout) { size_t i; @@ -328,7 +340,6 @@ static ssize_t wdt_write(struct file *file, const char __user *buf, size_t count /** * wdt_ioctl: - * @inode: inode of the device * @file: file handle to the device * @cmd: watchdog command * @arg: argument pointer @@ -338,8 +349,7 @@ static ssize_t wdt_write(struct file *file, const char __user *buf, size_t count * querying capabilities and current status. */ -static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) +static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; int __user *p = argp; @@ -362,32 +372,28 @@ static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ident.options |= WDIOF_FANFAULT; #endif /* CONFIG_WDT_501 */ - switch(cmd) - { - default: - return -ENOTTY; - case WDIOC_GETSUPPORT: - return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; - - case WDIOC_GETSTATUS: - wdt_get_status(&status); - return put_user(status, p); - case WDIOC_GETBOOTSTATUS: - return put_user(0, p); - case WDIOC_KEEPALIVE: - wdt_ping(); - return 0; - case WDIOC_SETTIMEOUT: - if (get_user(new_heartbeat, p)) - return -EFAULT; - - if (wdt_set_heartbeat(new_heartbeat)) - return -EINVAL; - - wdt_ping(); - /* Fall */ - case WDIOC_GETTIMEOUT: - return put_user(heartbeat, p); + switch (cmd) { + default: + return -ENOTTY; + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; + case WDIOC_GETSTATUS: + wdt_get_status(&status); + return put_user(status, p); + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + case WDIOC_KEEPALIVE: + wdt_ping(); + return 0; + case WDIOC_SETTIMEOUT: + if (get_user(new_heartbeat, p)) + return -EFAULT; + if (wdt_set_heartbeat(new_heartbeat)) + return -EINVAL; + wdt_ping(); + /* Fall */ + case WDIOC_GETTIMEOUT: + return put_user(heartbeat, p); } } @@ -405,7 +411,7 @@ static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static int wdt_open(struct inode *inode, struct file *file) { - if(test_and_set_bit(0, &wdt_is_open)) + if (test_and_set_bit(0, &wdt_is_open)) return -EBUSY; /* * Activate @@ -432,7 +438,8 @@ static int wdt_release(struct inode *inode, struct file *file) wdt_stop(); clear_bit(0, &wdt_is_open); } else { - printk(KERN_CRIT "wdt: WDT device closed unexpectedly. WDT will not stop!\n"); + printk(KERN_CRIT + "wdt: WDT device closed unexpectedly. WDT will not stop!\n"); wdt_ping(); } expect_close = 0; @@ -451,14 +458,15 @@ static int wdt_release(struct inode *inode, struct file *file) * farenheit. It was designed by an imperial measurement luddite. */ -static ssize_t wdt_temp_read(struct file *file, char __user *buf, size_t count, loff_t *ptr) +static ssize_t wdt_temp_read(struct file *file, char __user *buf, + size_t count, loff_t *ptr) { int temperature; if (wdt_get_temperature(&temperature)) return -EFAULT; - if (copy_to_user (buf, &temperature, 1)) + if (copy_to_user(buf, &temperature, 1)) return -EFAULT; return 1; @@ -506,10 +514,8 @@ static int wdt_temp_release(struct inode *inode, struct file *file) static int wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) { - if(code==SYS_DOWN || code==SYS_HALT) { - /* Turn the card off */ + if (code == SYS_DOWN || code == SYS_HALT) wdt_stop(); - } return NOTIFY_DONE; } @@ -522,7 +528,7 @@ static const struct file_operations wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = wdt_write, - .ioctl = wdt_ioctl, + .unlocked_ioctl = wdt_ioctl, .open = wdt_open, .release = wdt_release, }; @@ -576,7 +582,7 @@ static void __exit wdt_exit(void) #endif /* CONFIG_WDT_501 */ unregister_reboot_notifier(&wdt_notifier); free_irq(irq, NULL); - release_region(io,8); + release_region(io, 8); } /** @@ -591,44 +597,49 @@ static int __init wdt_init(void) { int ret; - /* Check that the heartbeat value is within it's range ; if not reset to the default */ + /* Check that the heartbeat value is within it's range; + if not reset to the default */ if (wdt_set_heartbeat(heartbeat)) { wdt_set_heartbeat(WD_TIMO); - printk(KERN_INFO "wdt: heartbeat value must be 0 #include #include +#include +#include -#include -#include #include #define WDT_IS_PCI @@ -73,7 +75,7 @@ /* We can only use 1 card due to the /dev/watchdog restriction */ static int dev_count; -static struct semaphore open_sem; +static unsigned long open_lock; static DEFINE_SPINLOCK(wdtpci_lock); static char expect_close; @@ -86,18 +88,23 @@ static int irq; static int heartbeat = WD_TIMO; static int wd_heartbeat; module_param(heartbeat, int, 0); -MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0>8, WDT_COUNT0+ctr); + outb(val & 0xFF, WDT_COUNT0 + ctr); + udelay(8); + outb(val >> 8, WDT_COUNT0 + ctr); + udelay(8); } /** @@ -134,23 +144,35 @@ static int wdtpci_start(void) * "pet" the watchdog, as Access says. * This resets the clock outputs. */ - inb_p(WDT_DC); /* Disable watchdog */ - wdtpci_ctr_mode(2,0); /* Program CTR2 for Mode 0: Pulse on Terminal Count */ - outb_p(0, WDT_DC); /* Enable watchdog */ - - inb_p(WDT_DC); /* Disable watchdog */ - outb_p(0, WDT_CLOCK); /* 2.0833MHz clock */ - inb_p(WDT_BUZZER); /* disable */ - inb_p(WDT_OPTONOTRST); /* disable */ - inb_p(WDT_OPTORST); /* disable */ - inb_p(WDT_PROGOUT); /* disable */ - wdtpci_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */ - wdtpci_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */ - wdtpci_ctr_mode(2,1); /* Program CTR2 for Mode 1: Retriggerable One-Shot */ - wdtpci_ctr_load(0,20833); /* count at 100Hz */ - wdtpci_ctr_load(1,wd_heartbeat);/* Heartbeat */ + inb(WDT_DC); /* Disable watchdog */ + udelay(8); + wdtpci_ctr_mode(2, 0); /* Program CTR2 for Mode 0: + Pulse on Terminal Count */ + outb(0, WDT_DC); /* Enable watchdog */ + udelay(8); + inb(WDT_DC); /* Disable watchdog */ + udelay(8); + outb(0, WDT_CLOCK); /* 2.0833MHz clock */ + udelay(8); + inb(WDT_BUZZER); /* disable */ + udelay(8); + inb(WDT_OPTONOTRST); /* disable */ + udelay(8); + inb(WDT_OPTORST); /* disable */ + udelay(8); + inb(WDT_PROGOUT); /* disable */ + udelay(8); + wdtpci_ctr_mode(0, 3); /* Program CTR0 for Mode 3: + Square Wave Generator */ + wdtpci_ctr_mode(1, 2); /* Program CTR1 for Mode 2: + Rate Generator */ + wdtpci_ctr_mode(2, 1); /* Program CTR2 for Mode 1: + Retriggerable One-Shot */ + wdtpci_ctr_load(0, 20833); /* count at 100Hz */ + wdtpci_ctr_load(1, wd_heartbeat);/* Heartbeat */ /* DO NOT LOAD CTR2 on PCI card! -- JPN */ - outb_p(0, WDT_DC); /* Enable watchdog */ + outb(0, WDT_DC); /* Enable watchdog */ + udelay(8); spin_unlock_irqrestore(&wdtpci_lock, flags); return 0; @@ -162,14 +184,15 @@ static int wdtpci_start(void) * Stop the watchdog driver. */ -static int wdtpci_stop (void) +static int wdtpci_stop(void) { unsigned long flags; /* Turn the card off */ spin_lock_irqsave(&wdtpci_lock, flags); - inb_p(WDT_DC); /* Disable watchdog */ - wdtpci_ctr_load(2,0); /* 0 length reset pulses now */ + inb(WDT_DC); /* Disable watchdog */ + udelay(8); + wdtpci_ctr_load(2, 0); /* 0 length reset pulses now */ spin_unlock_irqrestore(&wdtpci_lock, flags); return 0; } @@ -177,20 +200,23 @@ static int wdtpci_stop (void) /** * wdtpci_ping: * - * Reload counter one with the watchdog heartbeat. We don't bother reloading - * the cascade counter. + * Reload counter one with the watchdog heartbeat. We don't bother + * reloading the cascade counter. */ static int wdtpci_ping(void) { unsigned long flags; - /* Write a watchdog value */ spin_lock_irqsave(&wdtpci_lock, flags); - inb_p(WDT_DC); /* Disable watchdog */ - wdtpci_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */ - wdtpci_ctr_load(1,wd_heartbeat);/* Heartbeat */ - outb_p(0, WDT_DC); /* Enable watchdog */ + /* Write a watchdog value */ + inb(WDT_DC); /* Disable watchdog */ + udelay(8); + wdtpci_ctr_mode(1, 2); /* Re-Program CTR1 for Mode 2: + Rate Generator */ + wdtpci_ctr_load(1, wd_heartbeat);/* Heartbeat */ + outb(0, WDT_DC); /* Enable watchdog */ + udelay(8); spin_unlock_irqrestore(&wdtpci_lock, flags); return 0; } @@ -199,14 +225,14 @@ static int wdtpci_ping(void) * wdtpci_set_heartbeat: * @t: the new heartbeat value that needs to be set. * - * Set a new heartbeat value for the watchdog device. If the heartbeat value is - * incorrect we keep the old value and return -EINVAL. If successfull we - * return 0. + * Set a new heartbeat value for the watchdog device. If the heartbeat + * value is incorrect we keep the old value and return -EINVAL. + * If successful we return 0. */ static int wdtpci_set_heartbeat(int t) { /* Arbitrary, can't find the card's limits */ - if ((t < 1) || (t > 65535)) + if (t < 1 || t > 65535) return -EINVAL; heartbeat = t; @@ -227,9 +253,14 @@ static int wdtpci_set_heartbeat(int t) static int wdtpci_get_status(int *status) { - unsigned char new_status=inb_p(WDT_SR); + unsigned char new_status; + unsigned long flags; + + spin_lock_irqsave(&wdtpci_lock, flags); + new_status = inb(WDT_SR); + spin_unlock_irqrestore(&wdtpci_lock, flags); - *status=0; + *status = 0; if (new_status & WDC_SR_ISOI0) *status |= WDIOF_EXTERN1; if (new_status & WDC_SR_ISII1) @@ -259,8 +290,12 @@ static int wdtpci_get_status(int *status) static int wdtpci_get_temperature(int *temperature) { - unsigned short c=inb_p(WDT_RT); - + unsigned short c; + unsigned long flags; + spin_lock_irqsave(&wdtpci_lock, flags); + c = inb(WDT_RT); + udelay(8); + spin_unlock_irqrestore(&wdtpci_lock, flags); *temperature = (c * 11 / 15) + 7; return 0; } @@ -282,17 +317,25 @@ static irqreturn_t wdtpci_interrupt(int irq, void *dev_id) * Read the status register see what is up and * then printk it. */ - unsigned char status=inb_p(WDT_SR); + unsigned char status; + + spin_lock(&wdtpci_lock); + + status = inb(WDT_SR); + udelay(8); printk(KERN_CRIT PFX "status %d\n", status); #ifdef CONFIG_WDT_501_PCI - if (!(status & WDC_SR_TGOOD)) - printk(KERN_CRIT PFX "Overheat alarm.(%d)\n",inb_p(WDT_RT)); + if (!(status & WDC_SR_TGOOD)) { + u8 alarm = inb(WDT_RT); + printk(KERN_CRIT PFX "Overheat alarm.(%d)\n", alarm); + udelay(8); + } if (!(status & WDC_SR_PSUOVER)) - printk(KERN_CRIT PFX "PSU over voltage.\n"); + printk(KERN_CRIT PFX "PSU over voltage.\n"); if (!(status & WDC_SR_PSUUNDR)) - printk(KERN_CRIT PFX "PSU under voltage.\n"); + printk(KERN_CRIT PFX "PSU under voltage.\n"); if (tachometer) { if (!(status & WDC_SR_FANGOOD)) printk(KERN_CRIT PFX "Possible fan fault.\n"); @@ -310,6 +353,7 @@ static irqreturn_t wdtpci_interrupt(int irq, void *dev_id) printk(KERN_CRIT PFX "Reset in 5ms.\n"); #endif } + spin_unlock(&wdtpci_lock); return IRQ_HANDLED; } @@ -325,7 +369,8 @@ static irqreturn_t wdtpci_interrupt(int irq, void *dev_id) * write of data will do, as we we don't define content meaning. */ -static ssize_t wdtpci_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +static ssize_t wdtpci_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { if (count) { if (!nowayout) { @@ -335,7 +380,7 @@ static ssize_t wdtpci_write(struct file *file, const char __user *buf, size_t co for (i = 0; i != count; i++) { char c; - if(get_user(c, buf+i)) + if (get_user(c, buf+i)) return -EFAULT; if (c == 'V') expect_close = 42; @@ -343,13 +388,11 @@ static ssize_t wdtpci_write(struct file *file, const char __user *buf, size_t co } wdtpci_ping(); } - return count; } /** * wdtpci_ioctl: - * @inode: inode of the device * @file: file handle to the device * @cmd: watchdog command * @arg: argument pointer @@ -359,8 +402,8 @@ static ssize_t wdtpci_write(struct file *file, const char __user *buf, size_t co * querying capabilities and current status. */ -static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) +static long wdtpci_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { int new_heartbeat; int status; @@ -383,33 +426,29 @@ static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd ident.options |= WDIOF_FANFAULT; #endif /* CONFIG_WDT_501_PCI */ - switch(cmd) - { - default: - return -ENOTTY; - case WDIOC_GETSUPPORT: - return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; - - case WDIOC_GETSTATUS: - wdtpci_get_status(&status); - return put_user(status, p); - case WDIOC_GETBOOTSTATUS: - return put_user(0, p); - case WDIOC_KEEPALIVE: - wdtpci_ping(); - return 0; - case WDIOC_SETTIMEOUT: - if (get_user(new_heartbeat, p)) - return -EFAULT; - - if (wdtpci_set_heartbeat(new_heartbeat)) - return -EINVAL; - - wdtpci_ping(); - /* Fall */ - case WDIOC_GETTIMEOUT: - return put_user(heartbeat, p); - } + switch (cmd) { + default: + return -ENOTTY; + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; + case WDIOC_GETSTATUS: + wdtpci_get_status(&status); + return put_user(status, p); + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + case WDIOC_KEEPALIVE: + wdtpci_ping(); + return 0; + case WDIOC_SETTIMEOUT: + if (get_user(new_heartbeat, p)) + return -EFAULT; + if (wdtpci_set_heartbeat(new_heartbeat)) + return -EINVAL; + wdtpci_ping(); + /* Fall */ + case WDIOC_GETTIMEOUT: + return put_user(heartbeat, p); + } } /** @@ -426,12 +465,11 @@ static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd static int wdtpci_open(struct inode *inode, struct file *file) { - if (down_trylock(&open_sem)) + if (test_and_set_bit(0, &open_lock)) return -EBUSY; - if (nowayout) { + if (nowayout) __module_get(THIS_MODULE); - } /* * Activate */ @@ -460,7 +498,7 @@ static int wdtpci_release(struct inode *inode, struct file *file) wdtpci_ping(); } expect_close = 0; - up(&open_sem); + clear_bit(0, &open_lock); return 0; } @@ -476,14 +514,15 @@ static int wdtpci_release(struct inode *inode, struct file *file) * fahrenheit. It was designed by an imperial measurement luddite. */ -static ssize_t wdtpci_temp_read(struct file *file, char __user *buf, size_t count, loff_t *ptr) +static ssize_t wdtpci_temp_read(struct file *file, char __user *buf, + size_t count, loff_t *ptr) { int temperature; if (wdtpci_get_temperature(&temperature)) return -EFAULT; - if (copy_to_user (buf, &temperature, 1)) + if (copy_to_user(buf, &temperature, 1)) return -EFAULT; return 1; @@ -529,12 +568,10 @@ static int wdtpci_temp_release(struct inode *inode, struct file *file) */ static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) + void *unused) { - if (code==SYS_DOWN || code==SYS_HALT) { - /* Turn the card off */ + if (code == SYS_DOWN || code == SYS_HALT) wdtpci_stop(); - } return NOTIFY_DONE; } @@ -547,7 +584,7 @@ static const struct file_operations wdtpci_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = wdtpci_write, - .ioctl = wdtpci_ioctl, + .unlocked_ioctl = wdtpci_ioctl, .open = wdtpci_open, .release = wdtpci_release, }; @@ -584,80 +621,85 @@ static struct notifier_block wdtpci_notifier = { }; -static int __devinit wdtpci_init_one (struct pci_dev *dev, - const struct pci_device_id *ent) +static int __devinit wdtpci_init_one(struct pci_dev *dev, + const struct pci_device_id *ent) { int ret = -EIO; dev_count++; if (dev_count > 1) { - printk (KERN_ERR PFX "this driver only supports 1 device\n"); + printk(KERN_ERR PFX "This driver only supports one device\n"); return -ENODEV; } - if (pci_enable_device (dev)) { - printk (KERN_ERR PFX "Not possible to enable PCI Device\n"); + if (pci_enable_device(dev)) { + printk(KERN_ERR PFX "Not possible to enable PCI Device\n"); return -ENODEV; } - if (pci_resource_start (dev, 2) == 0x0000) { - printk (KERN_ERR PFX "No I/O-Address for card detected\n"); + if (pci_resource_start(dev, 2) == 0x0000) { + printk(KERN_ERR PFX "No I/O-Address for card detected\n"); ret = -ENODEV; goto out_pci; } - sema_init(&open_sem, 1); - irq = dev->irq; - io = pci_resource_start (dev, 2); + io = pci_resource_start(dev, 2); - if (request_region (io, 16, "wdt_pci") == NULL) { - printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", io); + if (request_region(io, 16, "wdt_pci") == NULL) { + printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", io); goto out_pci; } - if (request_irq (irq, wdtpci_interrupt, IRQF_DISABLED | IRQF_SHARED, + if (request_irq(irq, wdtpci_interrupt, IRQF_DISABLED | IRQF_SHARED, "wdt_pci", &wdtpci_miscdev)) { - printk (KERN_ERR PFX "IRQ %d is not free\n", irq); + printk(KERN_ERR PFX "IRQ %d is not free\n", irq); goto out_reg; } - printk ("PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%04x (Interrupt %d)\n", - io, irq); + printk(KERN_INFO + "PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%04x (Interrupt %d)\n", + io, irq); - /* Check that the heartbeat value is within it's range ; if not reset to the default */ + /* Check that the heartbeat value is within its range; + if not reset to the default */ if (wdtpci_set_heartbeat(heartbeat)) { wdtpci_set_heartbeat(WD_TIMO); - printk(KERN_INFO PFX "heartbeat value must be 0 Date: Mon, 4 Aug 2008 17:56:02 +0100 Subject: alpha: Fix breakage in wdt_pci drivers/watchdog/wdt_pci.c: In function 'wdtpci_ctr_mode': drivers/watchdog/wdt_pci.c:120: error: implicit declaration of function 'udelay' {standard input}: Assembler messages: Signed-off-by: Andrew Morton Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/watchdog/wdt_pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c index 078f37f8038..5d922fd6eaf 100644 --- a/drivers/watchdog/wdt_pci.c +++ b/drivers/watchdog/wdt_pci.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 103a1d5c57fac3623613b130b104f5b03367b31c Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 4 Aug 2008 17:56:28 +0100 Subject: sc1200 watchdog driver: Fix locking, sems and coding style Signed-off-by: Andrew Morton Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/watchdog/sc1200wdt.c | 205 ++++++++++++++++++++++++------------------- 1 file changed, 113 insertions(+), 92 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/sc1200wdt.c b/drivers/watchdog/sc1200wdt.c index 35cddff7020..621ebad56d8 100644 --- a/drivers/watchdog/sc1200wdt.c +++ b/drivers/watchdog/sc1200wdt.c @@ -15,14 +15,18 @@ * * Changelog: * 20020220 Zwane Mwaikambo Code based on datasheet, no hardware. - * 20020221 Zwane Mwaikambo Cleanups as suggested by Jeff Garzik and Alan Cox. + * 20020221 Zwane Mwaikambo Cleanups as suggested by Jeff Garzik + * and Alan Cox. * 20020222 Zwane Mwaikambo Added probing. * 20020225 Zwane Mwaikambo Added ISAPNP support. * 20020412 Rob Radez Broke out start/stop functions - * Return proper status instead of temperature warning - * Add WDIOC_GETBOOTSTATUS and WDIOC_SETOPTIONS ioctls + * Return proper status instead of + * temperature warning + * Add WDIOC_GETBOOTSTATUS and + * WDIOC_SETOPTIONS ioctls * Fix CONFIG_WATCHDOG_NOWAYOUT - * 20020530 Joel Becker Add Matt Domsch's nowayout module option + * 20020530 Joel Becker Add Matt Domsch's nowayout module + * option * 20030116 Adam Belay Updated to the latest pnp code * */ @@ -39,9 +43,8 @@ #include #include #include - -#include -#include +#include +#include #define SC1200_MODULE_VER "build 20020303" #define SC1200_MODULE_NAME "sc1200wdt" @@ -72,7 +75,7 @@ static char banner[] __initdata = KERN_INFO PFX SC1200_MODULE_VER; static int timeout = 1; static int io = -1; static int io_len = 2; /* for non plug and play */ -static struct semaphore open_sem; +static unsigned long open_flag; static char expect_close; static DEFINE_SPINLOCK(sc1200wdt_lock); /* io port access serialisation */ @@ -81,7 +84,8 @@ static int isapnp = 1; static struct pnp_dev *wdt_dev; module_param(isapnp, int, 0); -MODULE_PARM_DESC(isapnp, "When set to 0 driver ISA PnP support will be disabled"); +MODULE_PARM_DESC(isapnp, + "When set to 0 driver ISA PnP support will be disabled"); #endif module_param(io, int, 0); @@ -91,26 +95,40 @@ MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1"); static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +MODULE_PARM_DESC(nowayout, + "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* Read from Data Register */ -static inline void sc1200wdt_read_data(unsigned char index, unsigned char *data) +static inline void __sc1200wdt_read_data(unsigned char index, + unsigned char *data) { - spin_lock(&sc1200wdt_lock); outb_p(index, PMIR); *data = inb(PMDR); - spin_unlock(&sc1200wdt_lock); } +static void sc1200wdt_read_data(unsigned char index, unsigned char *data) +{ + spin_lock(&sc1200wdt_lock); + __sc1200wdt_read_data(index, data); + spin_unlock(&sc1200wdt_lock); +} /* Write to Data Register */ -static inline void sc1200wdt_write_data(unsigned char index, unsigned char data) +static inline void __sc1200wdt_write_data(unsigned char index, + unsigned char data) { - spin_lock(&sc1200wdt_lock); outb_p(index, PMIR); outb(data, PMDR); +} + +static inline void sc1200wdt_write_data(unsigned char index, + unsigned char data) +{ + spin_lock(&sc1200wdt_lock); + __sc1200wdt_write_data(index, data); spin_unlock(&sc1200wdt_lock); } @@ -118,22 +136,23 @@ static inline void sc1200wdt_write_data(unsigned char index, unsigned char data) static void sc1200wdt_start(void) { unsigned char reg; + spin_lock(&sc1200wdt_lock); - sc1200wdt_read_data(WDCF, ®); + __sc1200wdt_read_data(WDCF, ®); /* assert WDO when any of the following interrupts are triggered too */ reg |= (KBC_IRQ | MSE_IRQ | UART1_IRQ | UART2_IRQ); - sc1200wdt_write_data(WDCF, reg); + __sc1200wdt_write_data(WDCF, reg); /* set the timeout and get the ball rolling */ - sc1200wdt_write_data(WDTO, timeout); -} + __sc1200wdt_write_data(WDTO, timeout); + spin_unlock(&sc1200wdt_lock); +} static void sc1200wdt_stop(void) { sc1200wdt_write_data(WDTO, 0); } - /* This returns the status of the WDO signal, inactive high. */ static inline int sc1200wdt_status(void) { @@ -144,14 +163,13 @@ static inline int sc1200wdt_status(void) * KEEPALIVEPING which is a bit of a kludge because there's nothing * else for enabled/disabled status */ - return (ret & 0x01) ? 0 : WDIOF_KEEPALIVEPING; /* bits 1 - 7 are undefined */ + return (ret & 0x01) ? 0 : WDIOF_KEEPALIVEPING; } - static int sc1200wdt_open(struct inode *inode, struct file *file) { /* allow one at a time */ - if (down_trylock(&open_sem)) + if (test_and_set_bit(0, &open_flag)) return -EBUSY; if (timeout > MAX_TIMEOUT) @@ -164,71 +182,71 @@ static int sc1200wdt_open(struct inode *inode, struct file *file) } -static int sc1200wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static long sc1200wdt_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { int new_timeout; void __user *argp = (void __user *)arg; int __user *p = argp; - static struct watchdog_info ident = { - .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, + static const struct watchdog_info ident = { + .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | + WDIOF_MAGICCLOSE, .firmware_version = 0, .identity = "PC87307/PC97307", }; switch (cmd) { - default: - return -ENOTTY; - - case WDIOC_GETSUPPORT: - if (copy_to_user(argp, &ident, sizeof ident)) - return -EFAULT; - return 0; - - case WDIOC_GETSTATUS: - return put_user(sc1200wdt_status(), p); - - case WDIOC_GETBOOTSTATUS: - return put_user(0, p); - - case WDIOC_KEEPALIVE: - sc1200wdt_write_data(WDTO, timeout); - return 0; - case WDIOC_SETTIMEOUT: - if (get_user(new_timeout, p)) - return -EFAULT; + case WDIOC_GETSUPPORT: + if (copy_to_user(argp, &ident, sizeof ident)) + return -EFAULT; + return 0; - /* the API states this is given in secs */ - new_timeout /= 60; - if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) - return -EINVAL; + case WDIOC_GETSTATUS: + return put_user(sc1200wdt_status(), p); - timeout = new_timeout; - sc1200wdt_write_data(WDTO, timeout); - /* fall through and return the new timeout */ + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); - case WDIOC_GETTIMEOUT: - return put_user(timeout * 60, p); + case WDIOC_KEEPALIVE: + sc1200wdt_write_data(WDTO, timeout); + return 0; + + case WDIOC_SETTIMEOUT: + if (get_user(new_timeout, p)) + return -EFAULT; + /* the API states this is given in secs */ + new_timeout /= 60; + if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) + return -EINVAL; + timeout = new_timeout; + sc1200wdt_write_data(WDTO, timeout); + /* fall through and return the new timeout */ - case WDIOC_SETOPTIONS: - { - int options, retval = -EINVAL; + case WDIOC_GETTIMEOUT: + return put_user(timeout * 60, p); - if (get_user(options, p)) - return -EFAULT; + case WDIOC_SETOPTIONS: + { + int options, retval = -EINVAL; - if (options & WDIOS_DISABLECARD) { - sc1200wdt_stop(); - retval = 0; - } + if (get_user(options, p)) + return -EFAULT; - if (options & WDIOS_ENABLECARD) { - sc1200wdt_start(); - retval = 0; - } + if (options & WDIOS_DISABLECARD) { + sc1200wdt_stop(); + retval = 0; + } - return retval; + if (options & WDIOS_ENABLECARD) { + sc1200wdt_start(); + retval = 0; } + + return retval; + } + default: + return -ENOTTY; } } @@ -240,16 +258,18 @@ static int sc1200wdt_release(struct inode *inode, struct file *file) printk(KERN_INFO PFX "Watchdog disabled\n"); } else { sc1200wdt_write_data(WDTO, timeout); - printk(KERN_CRIT PFX "Unexpected close!, timeout = %d min(s)\n", timeout); + printk(KERN_CRIT PFX + "Unexpected close!, timeout = %d min(s)\n", timeout); } - up(&open_sem); + clear_bit(0, &open_flag); expect_close = 0; return 0; } -static ssize_t sc1200wdt_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) +static ssize_t sc1200wdt_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) { if (len) { if (!nowayout) { @@ -275,7 +295,8 @@ static ssize_t sc1200wdt_write(struct file *file, const char __user *data, size_ } -static int sc1200wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) +static int sc1200wdt_notify_sys(struct notifier_block *this, + unsigned long code, void *unused) { if (code == SYS_DOWN || code == SYS_HALT) sc1200wdt_stop(); @@ -284,23 +305,20 @@ static int sc1200wdt_notify_sys(struct notifier_block *this, unsigned long code, } -static struct notifier_block sc1200wdt_notifier = -{ +static struct notifier_block sc1200wdt_notifier = { .notifier_call = sc1200wdt_notify_sys, }; -static const struct file_operations sc1200wdt_fops = -{ +static const struct file_operations sc1200wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = sc1200wdt_write, - .ioctl = sc1200wdt_ioctl, + .unlocked_ioctl = sc1200wdt_ioctl, .open = sc1200wdt_open, .release = sc1200wdt_release, }; -static struct miscdevice sc1200wdt_miscdev = -{ +static struct miscdevice sc1200wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &sc1200wdt_fops, @@ -312,14 +330,14 @@ static int __init sc1200wdt_probe(void) /* The probe works by reading the PMC3 register's default value of 0x0e * there is one caveat, if the device disables the parallel port or any * of the UARTs we won't be able to detect it. - * Nb. This could be done with accuracy by reading the SID registers, but - * we don't have access to those io regions. + * NB. This could be done with accuracy by reading the SID registers, + * but we don't have access to those io regions. */ unsigned char reg; sc1200wdt_read_data(PMC3, ®); - reg &= 0x0f; /* we don't want the UART busy bits */ + reg &= 0x0f; /* we don't want the UART busy bits */ return (reg == 0x0e) ? 0 : -ENODEV; } @@ -332,7 +350,8 @@ static struct pnp_device_id scl200wdt_pnp_devices[] = { {.id = ""}, }; -static int scl200wdt_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id) +static int scl200wdt_pnp_probe(struct pnp_dev *dev, + const struct pnp_device_id *dev_id) { /* this driver only supports one card at a time */ if (wdt_dev || !isapnp) @@ -347,13 +366,14 @@ static int scl200wdt_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id return -EBUSY; } - printk(KERN_INFO "scl200wdt: PnP device found at io port %#x/%d\n", io, io_len); + printk(KERN_INFO "scl200wdt: PnP device found at io port %#x/%d\n", + io, io_len); return 0; } -static void scl200wdt_pnp_remove(struct pnp_dev * dev) +static void scl200wdt_pnp_remove(struct pnp_dev *dev) { - if (wdt_dev){ + if (wdt_dev) { release_region(io, io_len); wdt_dev = NULL; } @@ -375,8 +395,6 @@ static int __init sc1200wdt_init(void) printk("%s\n", banner); - sema_init(&open_sem, 1); - #if defined CONFIG_PNP if (isapnp) { ret = pnp_register_driver(&scl200wdt_pnp_driver); @@ -410,13 +428,16 @@ static int __init sc1200wdt_init(void) ret = register_reboot_notifier(&sc1200wdt_notifier); if (ret) { - printk(KERN_ERR PFX "Unable to register reboot notifier err = %d\n", ret); + printk(KERN_ERR PFX + "Unable to register reboot notifier err = %d\n", ret); goto out_io; } ret = misc_register(&sc1200wdt_miscdev); if (ret) { - printk(KERN_ERR PFX "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR); + printk(KERN_ERR PFX + "Unable to register miscdev on minor %d\n", + WATCHDOG_MINOR); goto out_rbt; } @@ -446,7 +467,7 @@ static void __exit sc1200wdt_exit(void) unregister_reboot_notifier(&sc1200wdt_notifier); #if defined CONFIG_PNP - if(isapnp) + if (isapnp) pnp_unregister_driver(&scl200wdt_pnp_driver); else #endif -- cgit v1.2.3 From 529ae9aaa08378cfe2a4350bded76f32cc8ff0ce Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sat, 2 Aug 2008 12:01:03 +0200 Subject: mm: rename page trylock Converting page lock to new locking bitops requires a change of page flag operation naming, so we might as well convert it to something nicer (!TestSetPageLocked_Lock => trylock_page, SetPageLocked => set_page_locked). This also facilitates lockdeping of page lock. Signed-off-by: Nick Piggin Acked-by: KOSAKI Motohiro Acked-by: Peter Zijlstra Acked-by: Andrew Morton Acked-by: Benjamin Herrenschmidt Signed-off-by: Linus Torvalds --- drivers/scsi/sg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index d3b8ebb8377..3d36270a8b4 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1747,7 +1747,7 @@ st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, */ flush_dcache_page(pages[i]); /* ?? Is locking needed? I don't think so */ - /* if (TestSetPageLocked(pages[i])) + /* if (!trylock_page(pages[i])) goto out_unlock; */ } -- cgit v1.2.3 From 2f751b67a8be698cec52f786910ef4f0beffe9a7 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 4 Aug 2008 23:17:34 -0700 Subject: tg3: Fix 'scheduling while atomic' errors This patch fixes the 'scheduling while atomic' errors introduced by commit 12dac0756d357325b107fe6ec24921ec38661839 ("tg3: adapt tg3 to use reworked PCI PM code"). The first hunk of the patch removes an unnecessary tg3_set_power_state() call. The chip will already be in the D0 state either due to a chip reset or through a previous call to tg3_set_power_state(). The second hunk of the patch moves the tg3_set_power_state() call outside the critical section guarded by tg3_full_lock() and tg3_full_unlock() functions. The power state of the device is and should be outside the lock's domain and all other tg3_set_power_state() calls support this. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 26aa37aa531..d2439b85a79 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7687,21 +7687,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) */ static int tg3_init_hw(struct tg3 *tp, int reset_phy) { - int err; - - /* Force the chip into D0. */ - err = tg3_set_power_state(tp, PCI_D0); - if (err) - goto out; - tg3_switch_clocks(tp); tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0); - err = tg3_reset_hw(tp, reset_phy); - -out: - return err; + return tg3_reset_hw(tp, reset_phy); } #define TG3_STAT_ADD32(PSTAT, REG) \ @@ -8016,13 +8006,11 @@ static int tg3_open(struct net_device *dev) netif_carrier_off(tp->dev); - tg3_full_lock(tp, 0); - err = tg3_set_power_state(tp, PCI_D0); - if (err) { - tg3_full_unlock(tp); + if (err) return err; - } + + tg3_full_lock(tp, 0); tg3_disable_ints(tp); tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; -- cgit v1.2.3 From 367fdcb4e401161e51aaee5d06b3f82098bafefc Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Aug 2008 18:16:55 +0200 Subject: ide: fix pre-EIDE SWDMA support on big-endian id->tDMA is of 'unsigned char' type so endianness is already correct and calling le16_to_cpu() is wrong. Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-dma.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 71c377a7bcf..adc68275585 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -649,11 +649,7 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode) if (id->field_valid & 2) { mask = id->dma_1word & hwif->swdma_mask; } else if (id->tDMA) { - /* - * ide_fix_driveid() doesn't convert ->tDMA to the - * CPU endianness so we need to do it here - */ - u8 mode = le16_to_cpu(id->tDMA); + u8 mode = id->tDMA; /* * if the mode is valid convert it to the mask -- cgit v1.2.3 From 242f44261e6c5fdc13e3cd12f949ab717dc37d58 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Aug 2008 18:16:56 +0200 Subject: ide: fix ide_fix_driveid() Fix byte-swapping for id->words161_175[], id->words206_254[] and id->words206_254[]. Luckily all words previously left in little-endian byte-order are marked as reserved so this fix shouldn't affect user-space applications. Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-iops.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index 8aae9176451..2cbadffe922 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -484,11 +484,11 @@ void ide_fix_driveid (struct hd_driveid *id) for (i = 0; i < 3; i++) id->words157_159[i] = __le16_to_cpu(id->words157_159[i]); id->cfa_power = __le16_to_cpu(id->cfa_power); - for (i = 0; i < 14; i++) + for (i = 0; i < 15; i++) id->words161_175[i] = __le16_to_cpu(id->words161_175[i]); - for (i = 0; i < 31; i++) + for (i = 0; i < 30; i++) id->words176_205[i] = __le16_to_cpu(id->words176_205[i]); - for (i = 0; i < 48; i++) + for (i = 0; i < 49; i++) id->words206_254[i] = __le16_to_cpu(id->words206_254[i]); id->integrity_word = __le16_to_cpu(id->integrity_word); # else -- cgit v1.2.3 From b5b9309d3415480b3e66314a1d6c89db58bff9de Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Aug 2008 18:16:58 +0200 Subject: remove unnecessary includes Following files don't need at all: - arch/mips/jazz/setup.c - arch/sh/boards/mach-systemh/irq.c - drivers/macintosh/mediabay.c - drivers/scsi/hptiop.c - drivers/usb/storage/freecom.c - arch/powerpc/include/asm/ide.h - init/main.c Cc: Christoph Hellwig Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/macintosh/mediabay.c | 1 - drivers/scsi/hptiop.c | 1 - drivers/usb/storage/freecom.c | 2 -- 3 files changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index b1e5b470525..d7e46d345d9 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index 74d12b58a26..a48e4990fe1 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c index 7a4d4567722..73ac7262239 100644 --- a/drivers/usb/storage/freecom.c +++ b/drivers/usb/storage/freecom.c @@ -26,8 +26,6 @@ * (http://www.freecom.de/) */ -#include - #include #include -- cgit v1.2.3 From d3e33ff59facec005e48ba3360502b73a04e4b4e Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Aug 2008 18:16:59 +0200 Subject: ide: fix regression caused by ide_device_{get,put}() addition (take 2) On Monday 28 July 2008, Benjamin Herrenschmidt wrote: [...] > Vector: 300 (Data Access) at [c58b7b80] > pc: c014f264: elv_may_queue+0x10/0x44 > lr: c0152750: get_request+0x2c/0x2c0 > sp: c58b7c30 > msr: 1032 > dar: c > dsisr: 40000000 > current = 0xc58aaae0 > pid = 854, comm = media-bay > enter ? for help > mon> t > [c58b7c40] c0152750 get_request+0x2c/0x2c0 > [c58b7c70] c0152a08 get_request_wait+0x24/0xec > [c58b7cc0] c0225674 ide_cd_queue_pc+0x58/0x1a0 > [c58b7d40] c022672c ide_cdrom_packet+0x9c/0xdc > [c58b7d70] c0261810 cdrom_get_disc_info+0x60/0xd0 > [c58b7dc0] c026208c cdrom_mrw_exit+0x1c/0x11c > [c58b7e30] c0260f7c unregister_cdrom+0x84/0xe8 > [c58b7e50] c022395c ide_cd_release+0x80/0x84 > [c58b7e70] c0163650 kref_put+0x54/0x6c > [c58b7e80] c0223884 ide_cd_put+0x40/0x5c > [c58b7ea0] c0211100 generic_ide_remove+0x28/0x3c > [c58b7eb0] c01e9d34 __device_release_driver+0x78/0xb4 > [c58b7ec0] c01e9e44 device_release_driver+0x28/0x44 > [c58b7ee0] c01e8f7c bus_remove_device+0xac/0xd8 > [c58b7f00] c01e7424 device_del+0x104/0x198 > [c58b7f20] c01e74d0 device_unregister+0x18/0x30 > [c58b7f40] c02121c4 __ide_port_unregister_devices+0x6c/0x88 > [c58b7f60] c0212398 ide_port_unregister_devices+0x38/0x80 > [c58b7f80] c0208ca4 media_bay_step+0x1cc/0x5c0 > [c58b7fb0] c0209124 media_bay_task+0x8c/0xcc > [c58b7fd0] c00485c0 kthread+0x48/0x84 > [c58b7ff0] c0011b20 kernel_thread+0x44/0x60 The guilty commit turned out to be 08da591e14cf87247ec09b17c350235157a92fc3 ("ide: add ide_device_{get,put}() helpers"). ide_device_put() is called before kref_put() in ide_cd_put() so IDE device is already gone by the time ide_cd_release() is reached. Fix it by calling ide_device_get() before kref_get() and ide_device_put() after kref_put() in all affected device drivers. v2: Brown paper bag time. In v1 cd->drive was referenced after dropping last reference on cd object (which could result in OOPS in ide_device_put() as reported/debugged by Mariusz Kozlowski). Fix it by caching cd->drive in the local variable (fix other device drivers too). Reported-by: Benjamin Herrenschmidt Reported-by: Mariusz Kozlowski Cc: FUJITA Tomonori Cc: Borislav Petkov Tested-by: Mariusz Kozlowski Tested-by: Benjamin Herrenschmidt Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-cd.c | 12 +++++++----- drivers/ide/ide-disk.c | 11 ++++++----- drivers/ide/ide-floppy.c | 11 ++++++----- drivers/ide/ide-tape.c | 11 ++++++----- drivers/scsi/ide-scsi.c | 11 ++++++----- 5 files changed, 31 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index e617cf08aef..e19caa1453a 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -66,11 +66,11 @@ static struct cdrom_info *ide_cd_get(struct gendisk *disk) mutex_lock(&idecd_ref_mutex); cd = ide_cd_g(disk); if (cd) { - kref_get(&cd->kref); - if (ide_device_get(cd->drive)) { - kref_put(&cd->kref, ide_cd_release); + if (ide_device_get(cd->drive)) cd = NULL; - } + else + kref_get(&cd->kref); + } mutex_unlock(&idecd_ref_mutex); return cd; @@ -78,9 +78,11 @@ static struct cdrom_info *ide_cd_get(struct gendisk *disk) static void ide_cd_put(struct cdrom_info *cd) { + ide_drive_t *drive = cd->drive; + mutex_lock(&idecd_ref_mutex); - ide_device_put(cd->drive); kref_put(&cd->kref, ide_cd_release); + ide_device_put(drive); mutex_unlock(&idecd_ref_mutex); } diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 28d85b410f7..68b9cf0138b 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -65,11 +65,10 @@ static struct ide_disk_obj *ide_disk_get(struct gendisk *disk) mutex_lock(&idedisk_ref_mutex); idkp = ide_disk_g(disk); if (idkp) { - kref_get(&idkp->kref); - if (ide_device_get(idkp->drive)) { - kref_put(&idkp->kref, ide_disk_release); + if (ide_device_get(idkp->drive)) idkp = NULL; - } + else + kref_get(&idkp->kref); } mutex_unlock(&idedisk_ref_mutex); return idkp; @@ -77,9 +76,11 @@ static struct ide_disk_obj *ide_disk_get(struct gendisk *disk) static void ide_disk_put(struct ide_disk_obj *idkp) { + ide_drive_t *drive = idkp->drive; + mutex_lock(&idedisk_ref_mutex); - ide_device_put(idkp->drive); kref_put(&idkp->kref, ide_disk_release); + ide_device_put(drive); mutex_unlock(&idedisk_ref_mutex); } diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index ca11a26746f..e9034c0125f 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -167,11 +167,10 @@ static struct ide_floppy_obj *ide_floppy_get(struct gendisk *disk) mutex_lock(&idefloppy_ref_mutex); floppy = ide_floppy_g(disk); if (floppy) { - kref_get(&floppy->kref); - if (ide_device_get(floppy->drive)) { - kref_put(&floppy->kref, idefloppy_cleanup_obj); + if (ide_device_get(floppy->drive)) floppy = NULL; - } + else + kref_get(&floppy->kref); } mutex_unlock(&idefloppy_ref_mutex); return floppy; @@ -179,9 +178,11 @@ static struct ide_floppy_obj *ide_floppy_get(struct gendisk *disk) static void ide_floppy_put(struct ide_floppy_obj *floppy) { + ide_drive_t *drive = floppy->drive; + mutex_lock(&idefloppy_ref_mutex); - ide_device_put(floppy->drive); kref_put(&floppy->kref, idefloppy_cleanup_obj); + ide_device_put(drive); mutex_unlock(&idefloppy_ref_mutex); } diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 82c2afe4d28..1bce84b5663 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -331,11 +331,10 @@ static struct ide_tape_obj *ide_tape_get(struct gendisk *disk) mutex_lock(&idetape_ref_mutex); tape = ide_tape_g(disk); if (tape) { - kref_get(&tape->kref); - if (ide_device_get(tape->drive)) { - kref_put(&tape->kref, ide_tape_release); + if (ide_device_get(tape->drive)) tape = NULL; - } + else + kref_get(&tape->kref); } mutex_unlock(&idetape_ref_mutex); return tape; @@ -343,9 +342,11 @@ static struct ide_tape_obj *ide_tape_get(struct gendisk *disk) static void ide_tape_put(struct ide_tape_obj *tape) { + ide_drive_t *drive = tape->drive; + mutex_lock(&idetape_ref_mutex); - ide_device_put(tape->drive); kref_put(&tape->kref, ide_tape_release); + ide_device_put(drive); mutex_unlock(&idetape_ref_mutex); } diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index b40a673985a..461331d3dc4 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -102,11 +102,10 @@ static struct ide_scsi_obj *ide_scsi_get(struct gendisk *disk) mutex_lock(&idescsi_ref_mutex); scsi = ide_scsi_g(disk); if (scsi) { - scsi_host_get(scsi->host); - if (ide_device_get(scsi->drive)) { - scsi_host_put(scsi->host); + if (ide_device_get(scsi->drive)) scsi = NULL; - } + else + scsi_host_get(scsi->host); } mutex_unlock(&idescsi_ref_mutex); return scsi; @@ -114,9 +113,11 @@ static struct ide_scsi_obj *ide_scsi_get(struct gendisk *disk) static void ide_scsi_put(struct ide_scsi_obj *scsi) { + ide_drive_t *drive = scsi->drive; + mutex_lock(&idescsi_ref_mutex); - ide_device_put(scsi->drive); scsi_host_put(scsi->host); + ide_device_put(drive); mutex_unlock(&idescsi_ref_mutex); } -- cgit v1.2.3 From c5bfc3757f1d843a8e1261840c1f53c5062f8e92 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 5 Aug 2008 18:17:01 +0200 Subject: ide: remove CONFIG_IDE_MAX_HWIFS The benefits of a user settable CONFIG_IDE_MAX_HWIFS have become pretty tiny and are no longer considered worth the trouble of an own option. Simply always #define MAX_HWIFS to 10. Signed-off-by: Adrian Bunk Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/Kconfig | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 130ef64b44f..a34758d2951 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -54,16 +54,6 @@ menuconfig IDE if IDE -config IDE_MAX_HWIFS - int "Max IDE interfaces" - depends on ALPHA || SUPERH || IA64 || EMBEDDED - range 1 10 - default 4 - help - This is the maximum number of IDE hardware interfaces that will - be supported by the driver. Make sure it is at least as high as - the number of IDE interfaces in your system. - config BLK_DEV_IDE tristate "Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support" ---help--- -- cgit v1.2.3 From 938bb03d188a1e688fb0bcae49788f540193e80a Mon Sep 17 00:00:00 2001 From: Petr Tesarik Date: Tue, 5 Aug 2008 18:17:02 +0200 Subject: ide-cd: fix endianity for the error message in cdrom_read_capacity Aesthetic regards aside, commit e8e7b9eb11c34ee18bde8b7011af41938d1ad667 still leaves a bug in the error message, because it uses the unconverted big-endian value for printk. Fix this by using a local variable in machine byte order. The result is correct, more readable, and also produces slightly shorter code on i386. Signed-off-by: Petr Tesarik Cc: Jens Axboe Cc: Jan Kara Cc: Andrew Morton Cc: Acked-by: Borislav Petkov [bart: __u32 -> u32] Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-cd.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index e19caa1453a..89a112d513a 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1307,6 +1307,7 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity, int stat; unsigned char cmd[BLK_MAX_CDB]; unsigned len = sizeof(capbuf); + u32 blocklen; memset(cmd, 0, BLK_MAX_CDB); cmd[0] = GPCMD_READ_CDVD_CAPACITY; @@ -1319,23 +1320,24 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity, /* * Sanity check the given block size */ - switch (capbuf.blocklen) { - case __constant_cpu_to_be32(512): - case __constant_cpu_to_be32(1024): - case __constant_cpu_to_be32(2048): - case __constant_cpu_to_be32(4096): + blocklen = be32_to_cpu(capbuf.blocklen); + switch (blocklen) { + case 512: + case 1024: + case 2048: + case 4096: break; default: printk(KERN_ERR "%s: weird block size %u\n", - drive->name, capbuf.blocklen); + drive->name, blocklen); printk(KERN_ERR "%s: default to 2kb block size\n", drive->name); - capbuf.blocklen = __constant_cpu_to_be32(2048); + blocklen = 2048; break; } *capacity = 1 + be32_to_cpu(capbuf.lba); - *sectors_per_frame = be32_to_cpu(capbuf.blocklen) >> SECTOR_BITS; + *sectors_per_frame = blocklen >> SECTOR_BITS; return 0; } -- cgit v1.2.3 From af744e3294d09d706c4eae26cffaaa68a8d40337 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 5 Aug 2008 18:17:02 +0200 Subject: cdrom: don't check CDC_PLAY_AUDIO in cdrom_count_tracks() According to MMC-3 (or any later versions) READ TOCs are mandatory commands and have nothing to do with CDC_PLAY_AUDIO. I have no idea why the check was put there in the first place but it now only breaks automatic actions on certain drives. Note that this test was only effective when ide-cdrom was being used as sr didn't mask CDC_PLAY_AUDIO according to the capabilities. Signed-off-by: Tejun Heo Acked-by: Jens Axboe Cc: Borislav Petkov Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/cdrom/cdrom.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index a5da3563265..d9d1b65d206 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -1436,10 +1436,6 @@ static void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype* tracks) tracks->xa=0; tracks->error=0; cdinfo(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n"); - if (!CDROM_CAN(CDC_PLAY_AUDIO)) { - tracks->error=CDS_NO_INFO; - return; - } /* Grab the TOC header so we can see how many tracks there are */ if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header))) { if (ret == -ENOMEDIUM) -- cgit v1.2.3 From 24307ffabd5b39bad443641f54b12ee2ba7a38ac Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Aug 2008 18:17:03 +0200 Subject: cs5520: add enablebits checking Based on sparse comments in OpenFirmware code (no Cx5510/Cx5520 datasheet here). This fixes 2.6.26 regression reported by TAKADA and caused by addition of warm-plug support. Tested-by: TAKADA Yoshihito Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/cs5520.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index c0364b287f1..151844fcbb0 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -96,6 +96,7 @@ static const struct ide_port_ops cs5520_port_ops = { static const struct ide_port_info cyrix_chipset __devinitdata = { .name = DRV_NAME, + .enablebits = { { 0x60, 0x01, 0x01 }, { 0x60, 0x02, 0x02 } }, .port_ops = &cs5520_port_ops, .host_flags = IDE_HFLAG_ISA_PORTS | IDE_HFLAG_CS5520, .pio_mask = ATA_PIO4, -- cgit v1.2.3 From 36de994809264f752e51b74e77a9c49091d14230 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Aug 2008 18:17:03 +0200 Subject: ide: ->quirkproc method cannot be marked __devinit Now that we have warm-plug support ->quirkproc method no longer can be be marked __devinit. Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/it821x.c | 2 +- drivers/ide/pci/siimage.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c index e16a1d113a2..3193390d487 100644 --- a/drivers/ide/pci/it821x.c +++ b/drivers/ide/pci/it821x.c @@ -443,7 +443,7 @@ static u8 __devinit it821x_cable_detect(ide_hwif_t *hwif) * final tuning that is needed, or fixups to work around bugs. */ -static void __devinit it821x_quirkproc(ide_drive_t *drive) +static void it821x_quirkproc(ide_drive_t *drive) { struct it821x_dev *itdev = ide_get_hwifdata(drive->hwif); struct hd_driveid *id = drive->id; diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index b8ad9ad6cf0..66ca2b2180d 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -639,7 +639,7 @@ static int is_dev_seagate_sata(ide_drive_t *drive) * that can occur before we know what drives are present. */ -static void __devinit sil_quirkproc(ide_drive_t *drive) +static void sil_quirkproc(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; -- cgit v1.2.3 From f454cbe8cd38b6d447e74ddaf012017fea42717e Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Aug 2008 18:17:04 +0200 Subject: ide: ->cable_detect method cannot be marked __devinit Now that we have warm-plug support ->cable_detect method no longer can be be marked __devinit. Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/arm/palm_bk3710.c | 2 +- drivers/ide/pci/aec62xx.c | 2 +- drivers/ide/pci/alim15x3.c | 2 +- drivers/ide/pci/amd74xx.c | 2 +- drivers/ide/pci/atiixp.c | 2 +- drivers/ide/pci/cmd64x.c | 2 +- drivers/ide/pci/cs5535.c | 2 +- drivers/ide/pci/hpt366.c | 2 +- drivers/ide/pci/it8213.c | 2 +- drivers/ide/pci/it821x.c | 2 +- drivers/ide/pci/jmicron.c | 2 +- drivers/ide/pci/pdc202xx_new.c | 2 +- drivers/ide/pci/pdc202xx_old.c | 2 +- drivers/ide/pci/piix.c | 2 +- drivers/ide/pci/scc_pata.c | 2 +- drivers/ide/pci/serverworks.c | 8 ++++---- drivers/ide/pci/siimage.c | 2 +- drivers/ide/pci/sis5513.c | 2 +- drivers/ide/pci/slc90e66.c | 2 +- drivers/ide/pci/tc86c001.c | 2 +- drivers/ide/pci/via82cxxx.c | 2 +- 21 files changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c index 3e842d60eae..f788fa5a977 100644 --- a/drivers/ide/arm/palm_bk3710.c +++ b/drivers/ide/arm/palm_bk3710.c @@ -309,7 +309,7 @@ static void __devinit palm_bk3710_chipinit(void __iomem *base) palm_bk3710_setpiomode(base, NULL, 1, 600, 0); } -static u8 __devinit palm_bk3710_cable_detect(ide_hwif_t *hwif) +static u8 palm_bk3710_cable_detect(ide_hwif_t *hwif) { return ATA_CBL_PATA80; } diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c index e0c8fe7d9fe..40644b6f1c0 100644 --- a/drivers/ide/pci/aec62xx.c +++ b/drivers/ide/pci/aec62xx.c @@ -160,7 +160,7 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev) return dev->irq; } -static u8 __devinit atp86x_cable_detect(ide_hwif_t *hwif) +static u8 atp86x_cable_detect(ide_hwif_t *hwif) { struct pci_dev *dev = to_pci_dev(hwif->dev); u8 ata66 = 0, mask = hwif->channel ? 0x02 : 0x01; diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index b582687e0cd..d647526af55 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -371,7 +371,7 @@ static int ali_cable_override(struct pci_dev *pdev) * FIXME: frobs bits that are not defined on newer ALi devicea */ -static u8 __devinit ali_cable_detect(ide_hwif_t *hwif) +static u8 ali_cable_detect(ide_hwif_t *hwif) { struct pci_dev *dev = to_pci_dev(hwif->dev); unsigned long flags; diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 2cea7bf51a0..1e66a960a96 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -175,7 +175,7 @@ static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev) return dev->irq; } -static u8 __devinit amd_cable_detect(ide_hwif_t *hwif) +static u8 amd_cable_detect(ide_hwif_t *hwif) { if ((amd_80w >> hwif->channel) & 1) return ATA_CBL_PATA80; diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c index 332f08f43b5..41f6cb6c163 100644 --- a/drivers/ide/pci/atiixp.c +++ b/drivers/ide/pci/atiixp.c @@ -119,7 +119,7 @@ static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed) spin_unlock_irqrestore(&atiixp_lock, flags); } -static u8 __devinit atiixp_cable_detect(ide_hwif_t *hwif) +static u8 atiixp_cable_detect(ide_hwif_t *hwif) { struct pci_dev *pdev = to_pci_dev(hwif->dev); u8 udma_mode = 0, ch = hwif->channel; diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c index 1360b4fa9fd..e064398e03b 100644 --- a/drivers/ide/pci/cmd64x.c +++ b/drivers/ide/pci/cmd64x.c @@ -354,7 +354,7 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev) return 0; } -static u8 __devinit cmd64x_cable_detect(ide_hwif_t *hwif) +static u8 cmd64x_cable_detect(ide_hwif_t *hwif) { struct pci_dev *dev = to_pci_dev(hwif->dev); u8 bmidecsr = 0, mask = hwif->channel ? 0x02 : 0x01; diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c index f7b50cdeefa..dd3dc23af99 100644 --- a/drivers/ide/pci/cs5535.c +++ b/drivers/ide/pci/cs5535.c @@ -153,7 +153,7 @@ static void cs5535_set_pio_mode(ide_drive_t *drive, const u8 pio) cs5535_set_speed(drive, XFER_PIO_0 + pio); } -static u8 __devinit cs5535_cable_detect(ide_hwif_t *hwif) +static u8 cs5535_cable_detect(ide_hwif_t *hwif) { struct pci_dev *dev = to_pci_dev(hwif->dev); u8 bit; diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 5271b246b88..748793a413a 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -1214,7 +1214,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev) return dev->irq; } -static u8 __devinit hpt3xx_cable_detect(ide_hwif_t *hwif) +static u8 hpt3xx_cable_detect(ide_hwif_t *hwif) { struct pci_dev *dev = to_pci_dev(hwif->dev); struct ide_host *host = pci_get_drvdata(dev); diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c index 6eba8f18826..652e47dd7e8 100644 --- a/drivers/ide/pci/it8213.c +++ b/drivers/ide/pci/it8213.c @@ -141,7 +141,7 @@ static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed) } } -static u8 __devinit it8213_cable_detect(ide_hwif_t *hwif) +static u8 it8213_cable_detect(ide_hwif_t *hwif) { struct pci_dev *dev = to_pci_dev(hwif->dev); u8 reg42h = 0; diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c index 3193390d487..b6dc723de70 100644 --- a/drivers/ide/pci/it821x.c +++ b/drivers/ide/pci/it821x.c @@ -428,7 +428,7 @@ static void it821x_set_dma_mode(ide_drive_t *drive, const u8 speed) * the needed logic onboard. */ -static u8 __devinit it821x_cable_detect(ide_hwif_t *hwif) +static u8 it821x_cable_detect(ide_hwif_t *hwif) { /* The reference driver also only does disk side */ return ATA_CBL_PATA80; diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c index 545b6e172d9..bb9d09d8f19 100644 --- a/drivers/ide/pci/jmicron.c +++ b/drivers/ide/pci/jmicron.c @@ -27,7 +27,7 @@ typedef enum { * Returns the cable type. */ -static u8 __devinit jmicron_cable_detect(ide_hwif_t *hwif) +static u8 jmicron_cable_detect(ide_hwif_t *hwif) { struct pci_dev *pdev = to_pci_dev(hwif->dev); diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index 998615fa285..0f609b72f47 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -193,7 +193,7 @@ static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio) } } -static u8 __devinit pdcnew_cable_detect(ide_hwif_t *hwif) +static u8 pdcnew_cable_detect(ide_hwif_t *hwif) { if (get_indexed_reg(hwif, 0x0b) & 0x04) return ATA_CBL_PATA40; diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index 6ff2def58da..de9a2740046 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c @@ -117,7 +117,7 @@ static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio) pdc202xx_set_mode(drive, XFER_PIO_0 + pio); } -static u8 __devinit pdc2026x_cable_detect(ide_hwif_t *hwif) +static u8 pdc2026x_cable_detect(ide_hwif_t *hwif) { struct pci_dev *dev = to_pci_dev(hwif->dev); u16 CIS, mask = hwif->channel ? (1 << 11) : (1 << 10); diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index 7fc3022dcf6..30cfc815fe3 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -256,7 +256,7 @@ static const struct ich_laptop ich_laptop[] = { { 0, } }; -static u8 __devinit piix_cable_detect(ide_hwif_t *hwif) +static u8 piix_cable_detect(ide_hwif_t *hwif) { struct pci_dev *pdev = to_pci_dev(hwif->dev); const struct ich_laptop *lap = &ich_laptop[0]; diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c index 94a7ab86423..6cde48bba6f 100644 --- a/drivers/ide/pci/scc_pata.c +++ b/drivers/ide/pci/scc_pata.c @@ -827,7 +827,7 @@ static void __devinit init_iops_scc(ide_hwif_t *hwif) init_mmio_iops_scc(hwif); } -static u8 __devinit scc_cable_detect(ide_hwif_t *hwif) +static u8 scc_cable_detect(ide_hwif_t *hwif) { return ATA_CBL_PATA80; } diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index d173f293772..c3bdc6e51a4 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -272,7 +272,7 @@ static unsigned int __devinit init_chipset_svwks(struct pci_dev *dev) return dev->irq; } -static u8 __devinit ata66_svwks_svwks(ide_hwif_t *hwif) +static u8 ata66_svwks_svwks(ide_hwif_t *hwif) { return ATA_CBL_PATA80; } @@ -284,7 +284,7 @@ static u8 __devinit ata66_svwks_svwks(ide_hwif_t *hwif) * Bit 14 clear = primary IDE channel does not have 80-pin cable. * Bit 14 set = primary IDE channel has 80-pin cable. */ -static u8 __devinit ata66_svwks_dell(ide_hwif_t *hwif) +static u8 ata66_svwks_dell(ide_hwif_t *hwif) { struct pci_dev *dev = to_pci_dev(hwif->dev); @@ -303,7 +303,7 @@ static u8 __devinit ata66_svwks_dell(ide_hwif_t *hwif) * * WARNING: this only works on Alpine hardware! */ -static u8 __devinit ata66_svwks_cobalt(ide_hwif_t *hwif) +static u8 ata66_svwks_cobalt(ide_hwif_t *hwif) { struct pci_dev *dev = to_pci_dev(hwif->dev); @@ -315,7 +315,7 @@ static u8 __devinit ata66_svwks_cobalt(ide_hwif_t *hwif) return ATA_CBL_PATA40; } -static u8 __devinit svwks_cable_detect(ide_hwif_t *hwif) +static u8 svwks_cable_detect(ide_hwif_t *hwif) { struct pci_dev *dev = to_pci_dev(hwif->dev); diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 66ca2b2180d..445ce6fbea3 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -679,7 +679,7 @@ static void __devinit init_iops_siimage(ide_hwif_t *hwif) * Check for the presence of an ATA66 capable cable on the interface. */ -static u8 __devinit sil_cable_detect(ide_hwif_t *hwif) +static u8 sil_cable_detect(ide_hwif_t *hwif) { struct pci_dev *dev = to_pci_dev(hwif->dev); unsigned long addr = siimage_selreg(hwif, 0); diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index cc95f90b53b..e5a4b42b4e3 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -518,7 +518,7 @@ static const struct sis_laptop sis_laptop[] = { { 0, } }; -static u8 __devinit sis_cable_detect(ide_hwif_t *hwif) +static u8 sis_cable_detect(ide_hwif_t *hwif) { struct pci_dev *pdev = to_pci_dev(hwif->dev); const struct sis_laptop *lap = &sis_laptop[0]; diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index 13d1fa491f2..866d6c65e3a 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -116,7 +116,7 @@ static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed) } } -static u8 __devinit slc90e66_cable_detect(ide_hwif_t *hwif) +static u8 slc90e66_cable_detect(ide_hwif_t *hwif) { struct pci_dev *dev = to_pci_dev(hwif->dev); u8 reg47 = 0, mask = hwif->channel ? 0x01 : 0x02; diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c index b1cb8a9ce5a..7fc88c375e5 100644 --- a/drivers/ide/pci/tc86c001.c +++ b/drivers/ide/pci/tc86c001.c @@ -131,7 +131,7 @@ static void tc86c001_dma_start(ide_drive_t *drive) ide_dma_start(drive); } -static u8 __devinit tc86c001_cable_detect(ide_hwif_t *hwif) +static u8 tc86c001_cable_detect(ide_hwif_t *hwif) { struct pci_dev *dev = to_pci_dev(hwif->dev); unsigned long sc_base = pci_resource_start(dev, 5); diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index 454d2bf62dc..a6b2cc83f29 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -352,7 +352,7 @@ static int via_cable_override(struct pci_dev *pdev) return 0; } -static u8 __devinit via82cxxx_cable_detect(ide_hwif_t *hwif) +static u8 via82cxxx_cable_detect(ide_hwif_t *hwif) { struct pci_dev *pdev = to_pci_dev(hwif->dev); struct ide_host *host = pci_get_drvdata(pdev); -- cgit v1.2.3 From 580da34847488b404218d1d7f53b156f245f5555 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 5 Aug 2008 13:05:17 -0400 Subject: Fix USB storage hang on command abort Okay, I found the cause of the hang. It is a simple bug in the USB scatter-gather library, caused by changes added in response to the S-G chaining modification. This patch (as1125) fixes a bug in the USB scatter-gather library. Early exit from the S-G initialization loop does not reset the count of outstanding URBs. Signed-off-by: Alan Stern Cc: Matthew Dharm Cc: David Brownell Cc: Alan Jenkins Cc: James Bottomley Cc: Greg KH Signed-off-by: Linus Torvalds --- drivers/usb/core/message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 2fcc06eb5e6..586d6f1376c 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -389,7 +389,6 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev, if (io->entries <= 0) return io->entries; - io->count = io->entries; io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags); if (!io->urbs) goto nomem; @@ -458,6 +457,7 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev, io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT; /* transaction state */ + io->count = io->entries; io->status = 0; io->bytes = 0; init_completion(&io->complete); -- cgit v1.2.3 From 594a8819774b09ee5bf72d23300489459ff1f882 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 5 Aug 2008 13:01:06 -0700 Subject: vt8623fb: fix kernel oops commit 20e061fb750d36ec0ffcb2e44ed7dafa9018223b Author: Ondrej Zajicek Date: Mon Apr 28 02:15:18 2008 -0700 fbdev: framebuffer_alloc() fixes Correct the dev arg of framebuffer_alloc() in arkfb, s3fb and vt8623fb. causes a null-pointer deref because "info->dev is NULL, info was just kzallocated". Signed-off-by: Ondrej Zajicek Reported-by: "MadLoisae@gmx.net" Tested-by: "MadLoisae@gmx.net" Cc: Alexey Dobriyan Cc: "Antonino A. Daplas" Cc: Krzysztof Helt Cc: [2.6.26.x] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/arkfb.c | 18 +++++++++--------- drivers/video/s3fb.c | 18 +++++++++--------- drivers/video/vt8623fb.c | 20 ++++++++++---------- 3 files changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index 38a1e8308c8..4bd569e479a 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -958,20 +958,20 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_ /* Prepare PCI device */ rc = pci_enable_device(dev); if (rc < 0) { - dev_err(info->dev, "cannot enable PCI device\n"); + dev_err(info->device, "cannot enable PCI device\n"); goto err_enable_device; } rc = pci_request_regions(dev, "arkfb"); if (rc < 0) { - dev_err(info->dev, "cannot reserve framebuffer region\n"); + dev_err(info->device, "cannot reserve framebuffer region\n"); goto err_request_regions; } par->dac = ics5342_init(ark_dac_read_regs, ark_dac_write_regs, info); if (! par->dac) { rc = -ENOMEM; - dev_err(info->dev, "RAMDAC initialization failed\n"); + dev_err(info->device, "RAMDAC initialization failed\n"); goto err_dac; } @@ -982,7 +982,7 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_ info->screen_base = pci_iomap(dev, 0, 0); if (! info->screen_base) { rc = -ENOMEM; - dev_err(info->dev, "iomap for framebuffer failed\n"); + dev_err(info->device, "iomap for framebuffer failed\n"); goto err_iomap; } @@ -1004,19 +1004,19 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_ rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8); if (! ((rc == 1) || (rc == 2))) { rc = -EINVAL; - dev_err(info->dev, "mode %s not found\n", mode_option); + dev_err(info->device, "mode %s not found\n", mode_option); goto err_find_mode; } rc = fb_alloc_cmap(&info->cmap, 256, 0); if (rc < 0) { - dev_err(info->dev, "cannot allocate colormap\n"); + dev_err(info->device, "cannot allocate colormap\n"); goto err_alloc_cmap; } rc = register_framebuffer(info); if (rc < 0) { - dev_err(info->dev, "cannot register framebugger\n"); + dev_err(info->device, "cannot register framebugger\n"); goto err_reg_fb; } @@ -1090,7 +1090,7 @@ static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state) struct fb_info *info = pci_get_drvdata(dev); struct arkfb_info *par = info->par; - dev_info(info->dev, "suspend\n"); + dev_info(info->device, "suspend\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -1121,7 +1121,7 @@ static int ark_pci_resume (struct pci_dev* dev) struct fb_info *info = pci_get_drvdata(dev); struct arkfb_info *par = info->par; - dev_info(info->dev, "resume\n"); + dev_info(info->device, "resume\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 2972f112dbe..8361bd0e3df 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -903,13 +903,13 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i /* Prepare PCI device */ rc = pci_enable_device(dev); if (rc < 0) { - dev_err(info->dev, "cannot enable PCI device\n"); + dev_err(info->device, "cannot enable PCI device\n"); goto err_enable_device; } rc = pci_request_regions(dev, "s3fb"); if (rc < 0) { - dev_err(info->dev, "cannot reserve framebuffer region\n"); + dev_err(info->device, "cannot reserve framebuffer region\n"); goto err_request_regions; } @@ -921,7 +921,7 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i info->screen_base = pci_iomap(dev, 0, 0); if (! info->screen_base) { rc = -ENOMEM; - dev_err(info->dev, "iomap for framebuffer failed\n"); + dev_err(info->device, "iomap for framebuffer failed\n"); goto err_iomap; } @@ -965,19 +965,19 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8); if (! ((rc == 1) || (rc == 2))) { rc = -EINVAL; - dev_err(info->dev, "mode %s not found\n", mode_option); + dev_err(info->device, "mode %s not found\n", mode_option); goto err_find_mode; } rc = fb_alloc_cmap(&info->cmap, 256, 0); if (rc < 0) { - dev_err(info->dev, "cannot allocate colormap\n"); + dev_err(info->device, "cannot allocate colormap\n"); goto err_alloc_cmap; } rc = register_framebuffer(info); if (rc < 0) { - dev_err(info->dev, "cannot register framebuffer\n"); + dev_err(info->device, "cannot register framebuffer\n"); goto err_reg_fb; } @@ -1053,7 +1053,7 @@ static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state) struct fb_info *info = pci_get_drvdata(dev); struct s3fb_info *par = info->par; - dev_info(info->dev, "suspend\n"); + dev_info(info->device, "suspend\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -1085,7 +1085,7 @@ static int s3_pci_resume(struct pci_dev* dev) struct s3fb_info *par = info->par; int err; - dev_info(info->dev, "resume\n"); + dev_info(info->device, "resume\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -1102,7 +1102,7 @@ static int s3_pci_resume(struct pci_dev* dev) if (err) { mutex_unlock(&(par->open_lock)); release_console_sem(); - dev_err(info->dev, "error %d enabling device for resume\n", err); + dev_err(info->device, "error %d enabling device for resume\n", err); return err; } pci_set_master(dev); diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index 4a484ee98f8..34aae7a2a62 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -677,13 +677,13 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi rc = pci_enable_device(dev); if (rc < 0) { - dev_err(info->dev, "cannot enable PCI device\n"); + dev_err(info->device, "cannot enable PCI device\n"); goto err_enable_device; } rc = pci_request_regions(dev, "vt8623fb"); if (rc < 0) { - dev_err(info->dev, "cannot reserve framebuffer region\n"); + dev_err(info->device, "cannot reserve framebuffer region\n"); goto err_request_regions; } @@ -696,14 +696,14 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi info->screen_base = pci_iomap(dev, 0, 0); if (! info->screen_base) { rc = -ENOMEM; - dev_err(info->dev, "iomap for framebuffer failed\n"); + dev_err(info->device, "iomap for framebuffer failed\n"); goto err_iomap_1; } par->mmio_base = pci_iomap(dev, 1, 0); if (! par->mmio_base) { rc = -ENOMEM; - dev_err(info->dev, "iomap for MMIO failed\n"); + dev_err(info->device, "iomap for MMIO failed\n"); goto err_iomap_2; } @@ -714,7 +714,7 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi if ((16 <= memsize1) && (memsize1 <= 64) && (memsize1 == memsize2)) info->screen_size = memsize1 << 20; else { - dev_err(info->dev, "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2); + dev_err(info->device, "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2); info->screen_size = 16 << 20; } @@ -731,19 +731,19 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8); if (! ((rc == 1) || (rc == 2))) { rc = -EINVAL; - dev_err(info->dev, "mode %s not found\n", mode_option); + dev_err(info->device, "mode %s not found\n", mode_option); goto err_find_mode; } rc = fb_alloc_cmap(&info->cmap, 256, 0); if (rc < 0) { - dev_err(info->dev, "cannot allocate colormap\n"); + dev_err(info->device, "cannot allocate colormap\n"); goto err_alloc_cmap; } rc = register_framebuffer(info); if (rc < 0) { - dev_err(info->dev, "cannot register framebugger\n"); + dev_err(info->device, "cannot register framebugger\n"); goto err_reg_fb; } @@ -817,7 +817,7 @@ static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state) struct fb_info *info = pci_get_drvdata(dev); struct vt8623fb_info *par = info->par; - dev_info(info->dev, "suspend\n"); + dev_info(info->device, "suspend\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -848,7 +848,7 @@ static int vt8623_pci_resume(struct pci_dev* dev) struct fb_info *info = pci_get_drvdata(dev); struct vt8623fb_info *par = info->par; - dev_info(info->dev, "resume\n"); + dev_info(info->device, "resume\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); -- cgit v1.2.3 From 756fcab27756f32722b748e2aff3393eef9a589d Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 5 Aug 2008 13:01:08 -0700 Subject: block/cciss.c: remove pointless curr_queue calculation curr_queue is a local variable in a for loop, and it's being initialized at the start of each loop. So any assignment at the end of the loop is pointless. Signed-off-by: Hannes Reinecke Cc: Mike Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/cciss.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index d81632cd7d0..0ce0c279aab 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1292,8 +1292,6 @@ static void cciss_check_queues(ctlr_info_t *h) h->next_to_run = curr_queue; break; } - } else { - curr_queue = (curr_queue + 1) % (h->highest_lun + 1); } } } -- cgit v1.2.3 From 60cadec9da7b6c91aca51f408c828f7e74a68379 Mon Sep 17 00:00:00 2001 From: Shadi Ammouri Date: Tue, 5 Aug 2008 13:01:09 -0700 Subject: spi: new orion_spi driver This adds an SPI driver for the SPI controller found in various Marvell Orion ARM SoCs. It currently supports only one slave, which must use SPI mode 0. [dbrownell@users.sourceforge.net: cleanups, meet specs, pass "sparse"] Signed-off-by: Shadi Ammouri Signed-off-by: Saeed Bishara Signed-off-by: Lennert Buytenhek Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/spi/Kconfig | 6 + drivers/spi/Makefile | 1 + drivers/spi/orion_spi.c | 574 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 581 insertions(+) create mode 100644 drivers/spi/orion_spi.c (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 2303521b4f0..b9d0efb6803 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -149,6 +149,12 @@ config SPI_OMAP24XX SPI master controller for OMAP24xx/OMAP34xx Multichannel SPI (McSPI) modules. +config SPI_ORION + tristate "Orion SPI master (EXPERIMENTAL)" + depends on PLAT_ORION && EXPERIMENTAL + help + This enables using the SPI master controller on the Orion chips. + config SPI_PXA2XX tristate "PXA2xx SSP SPI master" depends on ARCH_PXA && EXPERIMENTAL diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 7fca043ce72..ccf18de34e1 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o +obj-$(CONFIG_SPI_ORION) += orion_spi.o obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o diff --git a/drivers/spi/orion_spi.c b/drivers/spi/orion_spi.c new file mode 100644 index 00000000000..c4eaacd6e55 --- /dev/null +++ b/drivers/spi/orion_spi.c @@ -0,0 +1,574 @@ +/* + * orion_spi.c -- Marvell Orion SPI controller driver + * + * Author: Shadi Ammouri + * Copyright (C) 2007-2008 Marvell Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "orion_spi" + +#define ORION_NUM_CHIPSELECTS 1 /* only one slave is supported*/ +#define ORION_SPI_WAIT_RDY_MAX_LOOP 2000 /* in usec */ + +#define ORION_SPI_IF_CTRL_REG 0x00 +#define ORION_SPI_IF_CONFIG_REG 0x04 +#define ORION_SPI_DATA_OUT_REG 0x08 +#define ORION_SPI_DATA_IN_REG 0x0c +#define ORION_SPI_INT_CAUSE_REG 0x10 + +#define ORION_SPI_IF_8_16_BIT_MODE (1 << 5) +#define ORION_SPI_CLK_PRESCALE_MASK 0x1F + +struct orion_spi { + struct work_struct work; + + /* Lock access to transfer list. */ + spinlock_t lock; + + struct list_head msg_queue; + struct spi_master *master; + void __iomem *base; + unsigned int max_speed; + unsigned int min_speed; + struct orion_spi_info *spi_info; +}; + +static struct workqueue_struct *orion_spi_wq; + +static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg) +{ + return orion_spi->base + reg; +} + +static inline void +orion_spi_setbits(struct orion_spi *orion_spi, u32 reg, u32 mask) +{ + void __iomem *reg_addr = spi_reg(orion_spi, reg); + u32 val; + + val = readl(reg_addr); + val |= mask; + writel(val, reg_addr); +} + +static inline void +orion_spi_clrbits(struct orion_spi *orion_spi, u32 reg, u32 mask) +{ + void __iomem *reg_addr = spi_reg(orion_spi, reg); + u32 val; + + val = readl(reg_addr); + val &= ~mask; + writel(val, reg_addr); +} + +static int orion_spi_set_transfer_size(struct orion_spi *orion_spi, int size) +{ + if (size == 16) { + orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG, + ORION_SPI_IF_8_16_BIT_MODE); + } else if (size == 8) { + orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG, + ORION_SPI_IF_8_16_BIT_MODE); + } else { + pr_debug("Bad bits per word value %d (only 8 or 16 are " + "allowed).\n", size); + return -EINVAL; + } + + return 0; +} + +static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed) +{ + u32 tclk_hz; + u32 rate; + u32 prescale; + u32 reg; + struct orion_spi *orion_spi; + + orion_spi = spi_master_get_devdata(spi->master); + + tclk_hz = orion_spi->spi_info->tclk; + + /* + * the supported rates are: 4,6,8...30 + * round up as we look for equal or less speed + */ + rate = DIV_ROUND_UP(tclk_hz, speed); + rate = roundup(rate, 2); + + /* check if requested speed is too small */ + if (rate > 30) + return -EINVAL; + + if (rate < 4) + rate = 4; + + /* Convert the rate to SPI clock divisor value. */ + prescale = 0x10 + rate/2; + + reg = readl(spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG)); + reg = ((reg & ~ORION_SPI_CLK_PRESCALE_MASK) | prescale); + writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG)); + + return 0; +} + +/* + * called only when no transfer is active on the bus + */ +static int +orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) +{ + struct orion_spi *orion_spi; + unsigned int speed = spi->max_speed_hz; + unsigned int bits_per_word = spi->bits_per_word; + int rc; + + orion_spi = spi_master_get_devdata(spi->master); + + if ((t != NULL) && t->speed_hz) + speed = t->speed_hz; + + if ((t != NULL) && t->bits_per_word) + bits_per_word = t->bits_per_word; + + rc = orion_spi_baudrate_set(spi, speed); + if (rc) + return rc; + + return orion_spi_set_transfer_size(orion_spi, bits_per_word); +} + +static void orion_spi_set_cs(struct orion_spi *orion_spi, int enable) +{ + if (enable) + orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1); + else + orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1); +} + +static inline int orion_spi_wait_till_ready(struct orion_spi *orion_spi) +{ + int i; + + for (i = 0; i < ORION_SPI_WAIT_RDY_MAX_LOOP; i++) { + if (readl(spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG))) + return 1; + else + udelay(1); + } + + return -1; +} + +static inline int +orion_spi_write_read_8bit(struct spi_device *spi, + const u8 **tx_buf, u8 **rx_buf) +{ + void __iomem *tx_reg, *rx_reg, *int_reg; + struct orion_spi *orion_spi; + + orion_spi = spi_master_get_devdata(spi->master); + tx_reg = spi_reg(orion_spi, ORION_SPI_DATA_OUT_REG); + rx_reg = spi_reg(orion_spi, ORION_SPI_DATA_IN_REG); + int_reg = spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG); + + /* clear the interrupt cause register */ + writel(0x0, int_reg); + + if (tx_buf && *tx_buf) + writel(*(*tx_buf)++, tx_reg); + else + writel(0, tx_reg); + + if (orion_spi_wait_till_ready(orion_spi) < 0) { + dev_err(&spi->dev, "TXS timed out\n"); + return -1; + } + + if (rx_buf && *rx_buf) + *(*rx_buf)++ = readl(rx_reg); + + return 1; +} + +static inline int +orion_spi_write_read_16bit(struct spi_device *spi, + const u16 **tx_buf, u16 **rx_buf) +{ + void __iomem *tx_reg, *rx_reg, *int_reg; + struct orion_spi *orion_spi; + + orion_spi = spi_master_get_devdata(spi->master); + tx_reg = spi_reg(orion_spi, ORION_SPI_DATA_OUT_REG); + rx_reg = spi_reg(orion_spi, ORION_SPI_DATA_IN_REG); + int_reg = spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG); + + /* clear the interrupt cause register */ + writel(0x0, int_reg); + + if (tx_buf && *tx_buf) + writel(__cpu_to_le16(get_unaligned((*tx_buf)++)), tx_reg); + else + writel(0, tx_reg); + + if (orion_spi_wait_till_ready(orion_spi) < 0) { + dev_err(&spi->dev, "TXS timed out\n"); + return -1; + } + + if (rx_buf && *rx_buf) + put_unaligned(__le16_to_cpu(readl(rx_reg)), (*rx_buf)++); + + return 1; +} + +static unsigned int +orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) +{ + struct orion_spi *orion_spi; + unsigned int count; + int word_len; + + orion_spi = spi_master_get_devdata(spi->master); + word_len = spi->bits_per_word; + count = xfer->len; + + if (word_len == 8) { + const u8 *tx = xfer->tx_buf; + u8 *rx = xfer->rx_buf; + + do { + if (orion_spi_write_read_8bit(spi, &tx, &rx) < 0) + goto out; + count--; + } while (count); + } else if (word_len == 16) { + const u16 *tx = xfer->tx_buf; + u16 *rx = xfer->rx_buf; + + do { + if (orion_spi_write_read_16bit(spi, &tx, &rx) < 0) + goto out; + count -= 2; + } while (count); + } + +out: + return xfer->len - count; +} + + +static void orion_spi_work(struct work_struct *work) +{ + struct orion_spi *orion_spi = + container_of(work, struct orion_spi, work); + + spin_lock_irq(&orion_spi->lock); + while (!list_empty(&orion_spi->msg_queue)) { + struct spi_message *m; + struct spi_device *spi; + struct spi_transfer *t = NULL; + int par_override = 0; + int status = 0; + int cs_active = 0; + + m = container_of(orion_spi->msg_queue.next, struct spi_message, + queue); + + list_del_init(&m->queue); + spin_unlock_irq(&orion_spi->lock); + + spi = m->spi; + + /* Load defaults */ + status = orion_spi_setup_transfer(spi, NULL); + + if (status < 0) + goto msg_done; + + list_for_each_entry(t, &m->transfers, transfer_list) { + if (par_override || t->speed_hz || t->bits_per_word) { + par_override = 1; + status = orion_spi_setup_transfer(spi, t); + if (status < 0) + break; + if (!t->speed_hz && !t->bits_per_word) + par_override = 0; + } + + if (!cs_active) { + orion_spi_set_cs(orion_spi, 1); + cs_active = 1; + } + + if (t->len) + m->actual_length += + orion_spi_write_read(spi, t); + + if (t->delay_usecs) + udelay(t->delay_usecs); + + if (t->cs_change) { + orion_spi_set_cs(orion_spi, 0); + cs_active = 0; + } + } + +msg_done: + if (cs_active) + orion_spi_set_cs(orion_spi, 0); + + m->status = status; + m->complete(m->context); + + spin_lock_irq(&orion_spi->lock); + } + + spin_unlock_irq(&orion_spi->lock); +} + +static int __init orion_spi_reset(struct orion_spi *orion_spi) +{ + /* Verify that the CS is deasserted */ + orion_spi_set_cs(orion_spi, 0); + + return 0; +} + +static int orion_spi_setup(struct spi_device *spi) +{ + struct orion_spi *orion_spi; + + orion_spi = spi_master_get_devdata(spi->master); + + if (spi->mode) { + dev_err(&spi->dev, "setup: unsupported mode bits %x\n", + spi->mode); + return -EINVAL; + } + + if (spi->bits_per_word == 0) + spi->bits_per_word = 8; + + if ((spi->max_speed_hz == 0) + || (spi->max_speed_hz > orion_spi->max_speed)) + spi->max_speed_hz = orion_spi->max_speed; + + if (spi->max_speed_hz < orion_spi->min_speed) { + dev_err(&spi->dev, "setup: requested speed too low %d Hz\n", + spi->max_speed_hz); + return -EINVAL; + } + + /* + * baudrate & width will be set orion_spi_setup_transfer + */ + return 0; +} + +static int orion_spi_transfer(struct spi_device *spi, struct spi_message *m) +{ + struct orion_spi *orion_spi; + struct spi_transfer *t = NULL; + unsigned long flags; + + m->actual_length = 0; + m->status = 0; + + /* reject invalid messages and transfers */ + if (list_empty(&m->transfers) || !m->complete) + return -EINVAL; + + orion_spi = spi_master_get_devdata(spi->master); + + list_for_each_entry(t, &m->transfers, transfer_list) { + unsigned int bits_per_word = spi->bits_per_word; + + if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { + dev_err(&spi->dev, + "message rejected : " + "invalid transfer data buffers\n"); + goto msg_rejected; + } + + if ((t != NULL) && t->bits_per_word) + bits_per_word = t->bits_per_word; + + if ((bits_per_word != 8) && (bits_per_word != 16)) { + dev_err(&spi->dev, + "message rejected : " + "invalid transfer bits_per_word (%d bits)\n", + bits_per_word); + goto msg_rejected; + } + /*make sure buffer length is even when working in 16 bit mode*/ + if ((t != NULL) && (t->bits_per_word == 16) && (t->len & 1)) { + dev_err(&spi->dev, + "message rejected : " + "odd data length (%d) while in 16 bit mode\n", + t->len); + goto msg_rejected; + } + + if (t->speed_hz < orion_spi->min_speed) { + dev_err(&spi->dev, + "message rejected : " + "device min speed (%d Hz) exceeds " + "required transfer speed (%d Hz)\n", + orion_spi->min_speed, t->speed_hz); + goto msg_rejected; + } + } + + + spin_lock_irqsave(&orion_spi->lock, flags); + list_add_tail(&m->queue, &orion_spi->msg_queue); + queue_work(orion_spi_wq, &orion_spi->work); + spin_unlock_irqrestore(&orion_spi->lock, flags); + + return 0; +msg_rejected: + /* Message rejected and not queued */ + m->status = -EINVAL; + if (m->complete) + m->complete(m->context); + return -EINVAL; +} + +static int __init orion_spi_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct orion_spi *spi; + struct resource *r; + struct orion_spi_info *spi_info; + int status = 0; + + spi_info = pdev->dev.platform_data; + + master = spi_alloc_master(&pdev->dev, sizeof *spi); + if (master == NULL) { + dev_dbg(&pdev->dev, "master allocation failed\n"); + return -ENOMEM; + } + + if (pdev->id != -1) + master->bus_num = pdev->id; + + master->setup = orion_spi_setup; + master->transfer = orion_spi_transfer; + master->num_chipselect = ORION_NUM_CHIPSELECTS; + + dev_set_drvdata(&pdev->dev, master); + + spi = spi_master_get_devdata(master); + spi->master = master; + spi->spi_info = spi_info; + + spi->max_speed = DIV_ROUND_UP(spi_info->tclk, 4); + spi->min_speed = DIV_ROUND_UP(spi_info->tclk, 30); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (r == NULL) { + status = -ENODEV; + goto out; + } + + if (!request_mem_region(r->start, (r->end - r->start) + 1, + pdev->dev.bus_id)) { + status = -EBUSY; + goto out; + } + spi->base = ioremap(r->start, SZ_1K); + + INIT_WORK(&spi->work, orion_spi_work); + + spin_lock_init(&spi->lock); + INIT_LIST_HEAD(&spi->msg_queue); + + if (orion_spi_reset(spi) < 0) + goto out_rel_mem; + + status = spi_register_master(master); + if (status < 0) + goto out_rel_mem; + + return status; + +out_rel_mem: + release_mem_region(r->start, (r->end - r->start) + 1); + +out: + spi_master_put(master); + return status; +} + + +static int __exit orion_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master; + struct orion_spi *spi; + struct resource *r; + + master = dev_get_drvdata(&pdev->dev); + spi = spi_master_get_devdata(master); + + cancel_work_sync(&spi->work); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(r->start, (r->end - r->start) + 1); + + spi_unregister_master(master); + + return 0; +} + +MODULE_ALIAS("platform:" DRIVER_NAME); + +static struct platform_driver orion_spi_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .remove = __exit_p(orion_spi_remove), +}; + +static int __init orion_spi_init(void) +{ + orion_spi_wq = create_singlethread_workqueue( + orion_spi_driver.driver.name); + if (orion_spi_wq == NULL) + return -ENOMEM; + + return platform_driver_probe(&orion_spi_driver, orion_spi_probe); +} +module_init(orion_spi_init); + +static void __exit orion_spi_exit(void) +{ + flush_workqueue(orion_spi_wq); + platform_driver_unregister(&orion_spi_driver); + + destroy_workqueue(orion_spi_wq); +} +module_exit(orion_spi_exit); + +MODULE_DESCRIPTION("Orion SPI driver"); +MODULE_AUTHOR("Shadi Ammouri "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From dd279f6127c0f64dfb0055bc0adb97a284a08df3 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 5 Aug 2008 13:01:15 -0700 Subject: blackfin RTC driver: if we dont define irq_set_freq, the common rtc-dev layer will give us the same behavior of returning ENOTTY Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Bryan Wu Cc: David Brownell Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-bfin.c | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 8624f55d056..48ada599477 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -381,20 +381,6 @@ static int bfin_rtc_proc(struct device *dev, struct seq_file *seq) #undef yesno } -/** - * bfin_irq_set_freq - make sure hardware supports requested freq - * @dev: pointer to RTC device structure - * @freq: requested frequency rate - * - * The Blackfin RTC can only generate periodic events at 1 per - * second (1 Hz), so reject any attempt at changing it. - */ -static int bfin_irq_set_freq(struct device *dev, int freq) -{ - dev_dbg_stamp(dev); - return -ENOTTY; -} - static struct rtc_class_ops bfin_rtc_ops = { .open = bfin_rtc_open, .release = bfin_rtc_release, @@ -404,7 +390,6 @@ static struct rtc_class_ops bfin_rtc_ops = { .read_alarm = bfin_rtc_read_alarm, .set_alarm = bfin_rtc_set_alarm, .proc = bfin_rtc_proc, - .irq_set_freq = bfin_irq_set_freq, }; static int __devinit bfin_rtc_probe(struct platform_device *pdev) -- cgit v1.2.3 From 5aeb776d0c2bb1dd3ef01f4805929e2bc2923e7b Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Tue, 5 Aug 2008 13:01:17 -0700 Subject: blackfin RTC driver: Fix bug Only RTC interrupt can wake up deeper sleep core Signed-off-by: Sonic Zhang Signed-off-by: Bryan Wu Signed-off-by: Bryan Wu Cc: David Brownell Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-bfin.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers') diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 48ada599477..a568d29b074 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -430,6 +430,30 @@ static int __devexit bfin_rtc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int bfin_rtc_suspend(struct platform_device *pdev, pm_message_t state) +{ +#ifdef PM_WAKEUP_SIC_IWR + struct bfin_rtc *rtc = dev_get_drvdata(&pdev->dev); +#endif + bfin_rtc_reset(&pdev->dev); +#ifdef PM_WAKEUP_SIC_IWR + bfin_write_RTC_SWCNT(10); + bfin_rtc_int_set(rtc, RTC_ISTAT_STOPWATCH); +#endif + return 0; +} + +static int bfin_rtc_resume(struct platform_device *pdev) +{ +#ifdef PM_WAKEUP_SIC_IWR + struct bfin_rtc *rtc = dev_get_drvdata(&pdev->dev); + bfin_rtc_int_clear(rtc, RTC_ISTAT_STOPWATCH); +#endif + return 0; +} +#endif + static struct platform_driver bfin_rtc_driver = { .driver = { .name = "rtc-bfin", @@ -437,6 +461,10 @@ static struct platform_driver bfin_rtc_driver = { }, .probe = bfin_rtc_probe, .remove = __devexit_p(bfin_rtc_remove), +#ifdef CONFIG_PM + .suspend = bfin_rtc_suspend, + .resume = bfin_rtc_resume, +#endif }; static int __init bfin_rtc_init(void) -- cgit v1.2.3 From 813006f4bb4a39afdde8ab2e3559971c029d1dc0 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 5 Aug 2008 13:01:18 -0700 Subject: blackfin RTC driver: add support for power management framework Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Bryan Wu Cc: David Brownell Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-bfin.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index a568d29b074..23b991d41ef 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -2,7 +2,7 @@ * Blackfin On-Chip Real Time Clock Driver * Supports BF52[257]/BF53[123]/BF53[467]/BF54[24789] * - * Copyright 2004-2007 Analog Devices Inc. + * Copyright 2004-2008 Analog Devices Inc. * * Enter bugs at http://blackfin.uclinux.org/ * @@ -412,6 +412,8 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc); + device_init_wakeup(&pdev->dev, 1); + return 0; err: @@ -433,25 +435,28 @@ static int __devexit bfin_rtc_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bfin_rtc_suspend(struct platform_device *pdev, pm_message_t state) { -#ifdef PM_WAKEUP_SIC_IWR struct bfin_rtc *rtc = dev_get_drvdata(&pdev->dev); -#endif - bfin_rtc_reset(&pdev->dev); -#ifdef PM_WAKEUP_SIC_IWR - bfin_write_RTC_SWCNT(10); - bfin_rtc_int_set(rtc, RTC_ISTAT_STOPWATCH); -#endif + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(IRQ_RTC); + else + bfin_rtc_int_clear(rtc, -1); + return 0; } static int bfin_rtc_resume(struct platform_device *pdev) { -#ifdef PM_WAKEUP_SIC_IWR - struct bfin_rtc *rtc = dev_get_drvdata(&pdev->dev); - bfin_rtc_int_clear(rtc, RTC_ISTAT_STOPWATCH); -#endif + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(IRQ_RTC); + else + bfin_write_RTC_ISTAT(-1); + return 0; } +#else +# define bfin_rtc_suspend NULL +# define bfin_rtc_resume NULL #endif static struct platform_driver bfin_rtc_driver = { @@ -461,10 +466,8 @@ static struct platform_driver bfin_rtc_driver = { }, .probe = bfin_rtc_probe, .remove = __devexit_p(bfin_rtc_remove), -#ifdef CONFIG_PM .suspend = bfin_rtc_suspend, .resume = bfin_rtc_resume, -#endif }; static int __init bfin_rtc_init(void) -- cgit v1.2.3 From 605eb8b3c05e970caf71c48f693efe33c212fb7b Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 5 Aug 2008 13:01:18 -0700 Subject: blackfin RTC driver: don't bother passing the rtc struct down to bfin_rtc_int_{set,clear} since it isnt needed (shaves off ~100bytes) Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Bryan Wu Cc: David Brownell Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-bfin.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 23b991d41ef..56656dd6b2c 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -238,12 +238,12 @@ static void bfin_rtc_release(struct device *dev) free_irq(IRQ_RTC, dev); } -static void bfin_rtc_int_set(struct bfin_rtc *rtc, u16 rtc_int) +static void bfin_rtc_int_set(u16 rtc_int) { bfin_write_RTC_ISTAT(rtc_int); bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | rtc_int); } -static void bfin_rtc_int_clear(struct bfin_rtc *rtc, u16 rtc_int) +static void bfin_rtc_int_clear(u16 rtc_int) { bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & rtc_int); } @@ -252,7 +252,7 @@ static void bfin_rtc_int_set_alarm(struct bfin_rtc *rtc) /* Blackfin has different bits for whether the alarm is * more than 24 hours away. */ - bfin_rtc_int_set(rtc, (rtc->rtc_alarm.tm_yday == -1 ? RTC_ISTAT_ALARM : RTC_ISTAT_ALARM_DAY)); + bfin_rtc_int_set(rtc->rtc_alarm.tm_yday == -1 ? RTC_ISTAT_ALARM : RTC_ISTAT_ALARM_DAY); } static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { @@ -266,21 +266,21 @@ static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long ar switch (cmd) { case RTC_PIE_ON: dev_dbg_stamp(dev); - bfin_rtc_int_set(rtc, RTC_ISTAT_STOPWATCH); + bfin_rtc_int_set(RTC_ISTAT_STOPWATCH); bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq); break; case RTC_PIE_OFF: dev_dbg_stamp(dev); - bfin_rtc_int_clear(rtc, ~RTC_ISTAT_STOPWATCH); + bfin_rtc_int_clear(~RTC_ISTAT_STOPWATCH); break; case RTC_UIE_ON: dev_dbg_stamp(dev); - bfin_rtc_int_set(rtc, RTC_ISTAT_SEC); + bfin_rtc_int_set(RTC_ISTAT_SEC); break; case RTC_UIE_OFF: dev_dbg_stamp(dev); - bfin_rtc_int_clear(rtc, ~RTC_ISTAT_SEC); + bfin_rtc_int_clear(~RTC_ISTAT_SEC); break; case RTC_AIE_ON: @@ -289,7 +289,7 @@ static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long ar break; case RTC_AIE_OFF: dev_dbg_stamp(dev); - bfin_rtc_int_clear(rtc, ~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)); + bfin_rtc_int_clear(~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)); break; default: @@ -435,12 +435,10 @@ static int __devexit bfin_rtc_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bfin_rtc_suspend(struct platform_device *pdev, pm_message_t state) { - struct bfin_rtc *rtc = dev_get_drvdata(&pdev->dev); - if (device_may_wakeup(&pdev->dev)) enable_irq_wake(IRQ_RTC); else - bfin_rtc_int_clear(rtc, -1); + bfin_rtc_int_clear(-1); return 0; } -- cgit v1.2.3 From 3b128fe04a3087d6e974b87402dc6e75d3142186 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 5 Aug 2008 13:01:19 -0700 Subject: blackfin RTC driver: disable the write complete irq upon close Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Cc: David Brownell Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-bfin.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 56656dd6b2c..d53772f59ce 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -144,13 +144,13 @@ static void bfin_rtc_sync_pending(struct device *dev) * Initialize the RTC. Enable pre-scaler to scale RTC clock * to 1Hz and clear interrupt/status registers. */ -static void bfin_rtc_reset(struct device *dev) +static void bfin_rtc_reset(struct device *dev, u16 rtc_ictl) { struct bfin_rtc *rtc = dev_get_drvdata(dev); dev_dbg_stamp(dev); bfin_rtc_sync_pending(dev); bfin_write_RTC_PREN(0x1); - bfin_write_RTC_ICTL(RTC_ISTAT_WRITE_COMPLETE); + bfin_write_RTC_ICTL(rtc_ictl); bfin_write_RTC_SWCNT(0); bfin_write_RTC_ALARM(0); bfin_write_RTC_ISTAT(0xFFFF); @@ -226,7 +226,7 @@ static int bfin_rtc_open(struct device *dev) ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_SHARED, to_platform_device(dev)->name, dev); if (!ret) - bfin_rtc_reset(dev); + bfin_rtc_reset(dev, RTC_ISTAT_WRITE_COMPLETE); return ret; } @@ -234,7 +234,7 @@ static int bfin_rtc_open(struct device *dev) static void bfin_rtc_release(struct device *dev) { dev_dbg_stamp(dev); - bfin_rtc_reset(dev); + bfin_rtc_reset(dev, 0); free_irq(IRQ_RTC, dev); } -- cgit v1.2.3 From 140fab14aef093cedf87f69234474c04fdcec99c Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 5 Aug 2008 13:01:20 -0700 Subject: blackfin RTC driver: wait for the write complete interrupt complete before sleeping Since we use the write complete interrupt, wait for it to complete before sleeping so we don't wake right back up due to it Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Cc: David Brownell Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-bfin.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index d53772f59ce..e6b0470063e 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -435,9 +435,10 @@ static int __devexit bfin_rtc_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bfin_rtc_suspend(struct platform_device *pdev, pm_message_t state) { - if (device_may_wakeup(&pdev->dev)) + if (device_may_wakeup(&pdev->dev)) { enable_irq_wake(IRQ_RTC); - else + bfin_rtc_sync_pending(&pdev->dev); + } else bfin_rtc_int_clear(-1); return 0; -- cgit v1.2.3 From e12af37d9ee09c2ac6da26a51c77754dec09fed4 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 5 Aug 2008 13:01:21 -0700 Subject: blackfin RTC driver: convert PIE handling to irq_set_state() as pointed out by David Brownell Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Cc: David Brownell Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-bfin.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index e6b0470063e..ceebce7e0a0 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -264,16 +264,6 @@ static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long ar bfin_rtc_sync_pending(dev); switch (cmd) { - case RTC_PIE_ON: - dev_dbg_stamp(dev); - bfin_rtc_int_set(RTC_ISTAT_STOPWATCH); - bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq); - break; - case RTC_PIE_OFF: - dev_dbg_stamp(dev); - bfin_rtc_int_clear(~RTC_ISTAT_STOPWATCH); - break; - case RTC_UIE_ON: dev_dbg_stamp(dev); bfin_rtc_int_set(RTC_ISTAT_SEC); @@ -381,6 +371,23 @@ static int bfin_rtc_proc(struct device *dev, struct seq_file *seq) #undef yesno } +static int bfin_irq_set_state(struct device *dev, int enabled) +{ + struct bfin_rtc *rtc = dev_get_drvdata(dev); + + dev_dbg_stamp(dev); + + bfin_rtc_sync_pending(dev); + + if (enabled) { + bfin_rtc_int_set(RTC_ISTAT_STOPWATCH); + bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq); + } else + bfin_rtc_int_clear(~RTC_ISTAT_STOPWATCH); + + return 0; +} + static struct rtc_class_ops bfin_rtc_ops = { .open = bfin_rtc_open, .release = bfin_rtc_release, @@ -390,6 +397,7 @@ static struct rtc_class_ops bfin_rtc_ops = { .read_alarm = bfin_rtc_read_alarm, .set_alarm = bfin_rtc_set_alarm, .proc = bfin_rtc_proc, + .irq_set_state = bfin_irq_set_state, }; static int __devinit bfin_rtc_probe(struct platform_device *pdev) -- cgit v1.2.3 From 26cb8bb21b11245a53f79d9fa766537752f77d88 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 5 Aug 2008 13:01:21 -0700 Subject: blackfin RTC driver: drop PIE/stopwatch code since the hardware can only do a max of 1HZ and this same functionality is provided by UIE Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Cc: David Brownell Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-bfin.c | 46 ++++++++++++++-------------------------------- 1 file changed, 14 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index ceebce7e0a0..a1af4c27939 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -32,6 +32,15 @@ * writes to clear status registers complete immediately. */ +/* It may seem odd that there is no SWCNT code in here (which would be exposed + * via the periodic interrupt event, or PIE). Since the Blackfin RTC peripheral + * runs in units of seconds (N/HZ) but the Linux framework runs in units of HZ + * (2^N HZ), there is no point in keeping code that only provides 1 HZ PIEs. + * The same exact behavior can be accomplished by using the update interrupt + * event (UIE). Maybe down the line the RTC peripheral will suck less in which + * case we can re-introduce PIE support. + */ + #include #include #include @@ -151,7 +160,6 @@ static void bfin_rtc_reset(struct device *dev, u16 rtc_ictl) bfin_rtc_sync_pending(dev); bfin_write_RTC_PREN(0x1); bfin_write_RTC_ICTL(rtc_ictl); - bfin_write_RTC_SWCNT(0); bfin_write_RTC_ALARM(0); bfin_write_RTC_ISTAT(0xFFFF); rtc->rtc_wrote_regs = 0; @@ -194,14 +202,6 @@ static irqreturn_t bfin_rtc_interrupt(int irq, void *dev_id) } } - if (rtc_ictl & RTC_ISTAT_STOPWATCH) { - if (rtc_istat & RTC_ISTAT_STOPWATCH) { - bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH); - events |= RTC_PF | RTC_IRQF; - bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq); - } - } - if (rtc_ictl & RTC_ISTAT_SEC) { if (rtc_istat & RTC_ISTAT_SEC) { bfin_write_RTC_ISTAT(RTC_ISTAT_SEC); @@ -361,33 +361,14 @@ static int bfin_rtc_proc(struct device *dev, struct seq_file *seq) seq_printf(seq, "alarm_IRQ\t: %s\n" "wkalarm_IRQ\t: %s\n" - "seconds_IRQ\t: %s\n" - "periodic_IRQ\t: %s\n", + "seconds_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM), yesno(ictl & RTC_ISTAT_ALARM_DAY), - yesno(ictl & RTC_ISTAT_SEC), - yesno(ictl & RTC_ISTAT_STOPWATCH)); + yesno(ictl & RTC_ISTAT_SEC)); return 0; #undef yesno } -static int bfin_irq_set_state(struct device *dev, int enabled) -{ - struct bfin_rtc *rtc = dev_get_drvdata(dev); - - dev_dbg_stamp(dev); - - bfin_rtc_sync_pending(dev); - - if (enabled) { - bfin_rtc_int_set(RTC_ISTAT_STOPWATCH); - bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq); - } else - bfin_rtc_int_clear(~RTC_ISTAT_STOPWATCH); - - return 0; -} - static struct rtc_class_ops bfin_rtc_ops = { .open = bfin_rtc_open, .release = bfin_rtc_release, @@ -397,7 +378,6 @@ static struct rtc_class_ops bfin_rtc_ops = { .read_alarm = bfin_rtc_read_alarm, .set_alarm = bfin_rtc_set_alarm, .proc = bfin_rtc_proc, - .irq_set_state = bfin_irq_set_state, }; static int __devinit bfin_rtc_probe(struct platform_device *pdev) @@ -416,7 +396,9 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev) ret = PTR_ERR(rtc->rtc_dev); goto err; } - rtc->rtc_dev->irq_freq = 1; + + /* see comment at top of file about stopwatch/PIE */ + bfin_write_RTC_SWCNT(0); platform_set_drvdata(pdev, rtc); -- cgit v1.2.3 From 14563a4ec450f35c70fbe5f6ac5199e9d5a0edc5 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 5 Aug 2008 13:01:22 -0700 Subject: backlight: add more information output to pwm_backlight Make the error paths in the pwm_backlight driver more informative in the probe path, especially for the times that it finds an error. Cc: Russell King Signed-off-by: Ben Dooks Cc: Richard Purdie Acked-by: Krzysztof Helt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/pwm_bl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 6338d0e2fe0..441e5a707d3 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -68,8 +68,10 @@ static int pwm_backlight_probe(struct platform_device *pdev) struct pwm_bl_data *pb; int ret; - if (!data) + if (!data) { + dev_err(&pdev->dev, "failed to find platform data\n"); return -EINVAL; + } if (data->init) { ret = data->init(&pdev->dev); @@ -79,6 +81,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb = kzalloc(sizeof(*pb), GFP_KERNEL); if (!pb) { + dev_err(&pdev->dev, "no memory for state\n"); ret = -ENOMEM; goto err_alloc; } @@ -91,7 +94,8 @@ static int pwm_backlight_probe(struct platform_device *pdev) dev_err(&pdev->dev, "unable to request PWM for backlight\n"); ret = PTR_ERR(pb->pwm); goto err_pwm; - } + } else + dev_dbg(&pdev->dev, "got pwm for backlight\n"); bl = backlight_device_register(pdev->name, &pdev->dev, pb, &pwm_backlight_ops); -- cgit v1.2.3 From 8cd6819842b79953c61250c719f61e01e51dd8cd Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 5 Aug 2008 13:01:24 -0700 Subject: backlight: add MODULE_ALIAS() to pwm_backlight driver Add the missing MODULE_ALIAS() to the pwm_backlight driver. Cc: Russell King Signed-off-by: Ben Dooks Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/pwm_bl.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 441e5a707d3..ea07258565f 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -187,3 +187,5 @@ module_exit(pwm_backlight_exit); MODULE_DESCRIPTION("PWM based Backlight Driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pwm-backlight"); + -- cgit v1.2.3 From efc491814308f89d5ef6c4fe19ae4552a67d4132 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 5 Aug 2008 13:01:25 -0700 Subject: radeon: misc corrections I have a new PCI-E radeon RV380 series card (PCI device ID 5b64) that hangs in my sparc64 boxes when the init scripts set the font. The problem goes away if I disable acceleration. I haven't figured out that bug yet, but along the way I found some corrections to make based upon some auditing. 1) The RB2D_DC_FLUSH_ALL value used by the kernel fb driver and the XORG video driver differ. I've made the kernel match what XORG is using. 2) In radeonfb_engine_reset() we have top-level code structure that roughly looks like: if (family is 300, 350, or V350) do this; else do that; ... if (family is NOT 300, OR family is NOT 350, OR family is NOT V350) do another thing; this last conditional makes no sense, is always true, and obviously was likely meant to be "family is NOT 300, 350, or V350". So I've made the code match the intent. Signed-off-by: David S. Miller Acked-by: Benjamin Herrenschmidt Tested-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/aty/radeon_accel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/aty/radeon_accel.c b/drivers/video/aty/radeon_accel.c index 3ca27cb13ca..4d13f68436e 100644 --- a/drivers/video/aty/radeon_accel.c +++ b/drivers/video/aty/radeon_accel.c @@ -241,8 +241,8 @@ void radeonfb_engine_reset(struct radeonfb_info *rinfo) INREG(HOST_PATH_CNTL); OUTREG(HOST_PATH_CNTL, host_path_cntl); - if (rinfo->family != CHIP_FAMILY_R300 || - rinfo->family != CHIP_FAMILY_R350 || + if (rinfo->family != CHIP_FAMILY_R300 && + rinfo->family != CHIP_FAMILY_R350 && rinfo->family != CHIP_FAMILY_RV350) OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset); -- cgit v1.2.3 From c213ddf330e29f9d141705444dc45683adbb99b0 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Tue, 5 Aug 2008 13:01:26 -0700 Subject: fbcon: fix scrolling after logo is cleared If the 'clear' command is used on the frame buffer with a logo the upper area is filled by few lines but not scrolled anymore. Fix this by removing the protected area for the logo if any part of the logo is cleared. Signed-off-by: Krzysztof Helt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/console/fbcon.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 3ccfa76d9b2..33859934a8e 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -1311,6 +1311,9 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, if (!height || !width) return; + if (sy < vc->vc_top && vc->vc_top == logo_lines) + vc->vc_top = 0; + /* Split blits that cross physical y_wrap boundary */ y_break = p->vrows - p->yscroll; -- cgit v1.2.3 From 9bd6ceb666e76b9a3caefa158827a571ead55b6a Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 5 Aug 2008 13:01:27 -0700 Subject: radeonfb: give i2c buses nicer names The name of the i2c buses shows in the output of "i2cdetect -l", so it's important to give informative names. Signed-off-by: Jean Delvare Acked-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/aty/radeon_i2c.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c index f9e7c29ad9b..8c8fa35f1b7 100644 --- a/drivers/video/aty/radeon_i2c.c +++ b/drivers/video/aty/radeon_i2c.c @@ -69,7 +69,8 @@ static int radeon_setup_i2c_bus(struct radeon_i2c_chan *chan, const char *name) { int rc; - strcpy(chan->adapter.name, name); + snprintf(chan->adapter.name, sizeof(chan->adapter.name), + "radeonfb %s", name); chan->adapter.owner = THIS_MODULE; chan->adapter.id = I2C_HW_B_RADEON; chan->adapter.algo_data = &chan->algo; -- cgit v1.2.3 From 5394ba0fd892291eb425649fdbc82b673e0b7956 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 5 Aug 2008 13:01:28 -0700 Subject: drivers/video/fsl-diu-fb.c: add missing of_node_put of_node_put is needed before discarding a value received from of_find_node_by_type, eg in error handling code. The semantic patch that makes the change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ struct device_node *n; struct device_node *n1; struct device_node *n2; statement S; identifier f1,f2; expression E1,E2; constant C; @@ n = of_find_node_by_type(...) ... if (!n) S ... when != of_node_put(n) when != n1 = f1(n,...) when != E1 = n when any when strict ( + of_node_put(n); return -C; | of_node_put(n); | n2 = f2(n,...) | E2 = n | return ...; ) // Signed-off-by: Julia Lawall Acked-by: Krzysztof Helt Cc: Timur Tabi Cc: York Sun Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/fsl-diu-fb.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index 9cd36c223d3..bd320a2bfb7 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -1649,8 +1649,10 @@ static int __init fsl_diu_init(void) } prop = of_get_property(np, "d-cache-size", NULL); - if (prop == NULL) + if (prop == NULL) { + of_node_put(np); return -ENODEV; + } /* Freescale PLRU requires 13/8 times the cache size to do a proper displacement flush @@ -1659,8 +1661,10 @@ static int __init fsl_diu_init(void) coherence_data_size /= 8; prop = of_get_property(np, "d-cache-line-size", NULL); - if (prop == NULL) + if (prop == NULL) { + of_node_put(np); return -ENODEV; + } d_cache_line_size = *prop; of_node_put(np); -- cgit v1.2.3 From 978cc90c469b38bcbbfd00a8c183d74e5b17bf45 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Tue, 5 Aug 2008 13:01:29 -0700 Subject: atyfb_base.c: fix warning drivers/video/aty/atyfb_base.c:2663: warning: 'aty_resume_chip' defined but not used Signed-off-by: Alexander Beregalov Cc: Ville Syrjala Cc: Antonino A. Daplas Cc: Mark Asselstine Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/aty/atyfb_base.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 620ba812036..cc6b470073d 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -244,7 +244,7 @@ static int atyfb_sync(struct fb_info *info); */ static int aty_init(struct fb_info *info); -static void aty_resume_chip(struct fb_info *info); + #ifdef CONFIG_ATARI static int store_video_par(char *videopar, unsigned char m64_num); #endif @@ -2023,6 +2023,20 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } +static void aty_resume_chip(struct fb_info *info) +{ + struct atyfb_par *par = info->par; + + aty_st_le32(MEM_CNTL, par->mem_cntl, par); + + if (par->pll_ops->resume_pll) + par->pll_ops->resume_pll(info, &par->pll); + + if (par->aux_start) + aty_st_le32(BUS_CNTL, + aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par); +} + static int atyfb_pci_resume(struct pci_dev *pdev) { struct fb_info *info = pci_get_drvdata(pdev); @@ -2659,19 +2673,6 @@ aty_init_exit: return ret; } -static void aty_resume_chip(struct fb_info *info) -{ - struct atyfb_par *par = info->par; - - aty_st_le32(MEM_CNTL, par->mem_cntl, par); - - if (par->pll_ops->resume_pll) - par->pll_ops->resume_pll(info, &par->pll); - - if (par->aux_start) - aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par); -} - #ifdef CONFIG_ATARI static int __devinit store_video_par(char *video_str, unsigned char m64_num) { -- cgit v1.2.3 From dc39778f952a820b7da45756a900a4778da343cd Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Tue, 5 Aug 2008 13:01:33 -0700 Subject: drivers/misc/sgi-gru/grutlbpurge.c: removed duplicated #include Removed duplicated include in drivers/misc/sgi-gru/grutlbpurge.c. Signed-off-by: Huang Weiyi Cc: Jack Steiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-gru/grutlbpurge.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-gru/grutlbpurge.c b/drivers/misc/sgi-gru/grutlbpurge.c index bcfd5425e2e..c84496a7769 100644 --- a/drivers/misc/sgi-gru/grutlbpurge.c +++ b/drivers/misc/sgi-gru/grutlbpurge.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include "gru.h" -- cgit v1.2.3 From 8c275ce327447f4cf3d0904d1a5a6ffa1b92de7f Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 5 Aug 2008 13:01:42 -0700 Subject: drivers/media/video/vino.c needs v4l2-ioctl.h mips allmodconfig: drivers/media/video/vino.c: In function `vino_free_buffer_with_count': drivers/media/video/vino.c:811: warning: passing arg 1 of `virt_to_phys' makes pointer from integer without a cast drivers/media/video/vino.c: In function `vino_allocate_buffer': drivers/media/video/vino.c:889: warning: passing arg 1 of `virt_to_phys' makes pointer from integer without a cast drivers/media/video/vino.c: In function `vino_ioctl': drivers/media/video/vino.c:4364: error: implicit declaration of function `video_usercopy' The patch fixes the error, but not the warnings. Cc: Mauro Carvalho Chehab Cc: Hans Verkuil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/vino.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index 3989b0eded2..ef7572cbc4a 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -39,6 +39,7 @@ #include #include +#include #include #include #include -- cgit v1.2.3 From 18351070b86d155713cf790b26af4f21b1fd0b29 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 5 Aug 2008 21:42:21 -0700 Subject: Re-introduce "[SCSI] extend the last_sector_bug flag to cover more sectors" This re-introduces commit 2b142900784c6e38c8d39fa57d5f95ef08e735d8, which was reverted due to the regression it caused by commit fca082c9f1e11ec07efa8d2f9f13688521253f36. That regression was not root-caused by the original commit, it was just uncovered by it, and the real fix was done by Alan Stern in commit 580da34847488b404218d1d7f53b156f245f5555 ("Fix USB storage hang on command abort"). We can thus re-introduce the change that was confirmed by Alan Jenkins to be still required by his odd card reader. Cc: Alan Jenkins Cc: Alan Stern Cc: James Bottomley Signed-off-by: Linus Torvalds --- drivers/scsi/sd.c | 21 +++++++++++++++------ drivers/scsi/sd.h | 6 ++++++ 2 files changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 8e08d51a0f0..e5e7d785645 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -375,6 +375,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) struct gendisk *disk = rq->rq_disk; struct scsi_disk *sdkp; sector_t block = rq->sector; + sector_t threshold; unsigned int this_count = rq->nr_sectors; unsigned int timeout = sdp->timeout; int ret; @@ -422,13 +423,21 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) } /* - * Some devices (some sdcards for one) don't like it if the - * last sector gets read in a larger then 1 sector read. + * Some SD card readers can't handle multi-sector accesses which touch + * the last one or two hardware sectors. Split accesses as needed. */ - if (unlikely(sdp->last_sector_bug && - rq->nr_sectors > sdp->sector_size / 512 && - block + this_count == get_capacity(disk))) - this_count -= sdp->sector_size / 512; + threshold = get_capacity(disk) - SD_LAST_BUGGY_SECTORS * + (sdp->sector_size / 512); + + if (unlikely(sdp->last_sector_bug && block + this_count > threshold)) { + if (block < threshold) { + /* Access up to the threshold but not beyond */ + this_count = threshold - block; + } else { + /* Access only a single hardware sector */ + this_count = sdp->sector_size / 512; + } + } SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n", (unsigned long long)block)); diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 550b2f70a1f..95b9f06534d 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -31,6 +31,12 @@ */ #define SD_BUF_SIZE 512 +/* + * Number of sectors at the end of the device to avoid multi-sector + * accesses to in the case of last_sector_bug + */ +#define SD_LAST_BUGGY_SECTORS 8 + struct scsi_disk { struct scsi_driver *driver; /* always &sd_template */ struct scsi_device *device; -- cgit v1.2.3